POJ - 3071
概率题。
1:爆枚
本蒟蒻不会概率dp,于是手搓枚举。
大抵是这么枚的:
如果区间里有它,好办,只能它赢
没他呢?就只能分类讨论。
中道崩殂的代码:
#include<iostream>
#include<vector>
#include<string.h>
using namespace std;
double p[130][130],dp[130];
int tree[520];
struct SadBee{
int who,what,where,l,r;
};
void bfs(int who,int what,int where,int l,int r){
vector<SadBee> a;
SadBee yzc={ who, what, where, l, r};
a.push_back(yzc);
while(a.size()){
//略
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,m;
cin>>n;
m=1<<n;
for(int i=1;i<=m;i++)for(int j=1;j<=m;j++)cin>>p[i][j];
for(int i=1;i<=m;i++)bfs(i,1.0,1,1,m);
}
时间复杂度高达 2^{2^{n}} ……(什么鬼渲染QAQ)
2:SadBee的想法反正不是爆枚
考虑维护每队对上上一队/下一队的胜率。
只有两队最简单,用1乘即可
那多队呢?不如看成两队。
见:
who win | how to win |
---|---|
P(1 胜) | = P(1 战胜 2)P(3 战胜 4)P(1 战胜 3) + P(1 战胜 2)P(4 战胜 3)P(1 战胜 4) |
P(2 胜) | = P(2 战胜 1)P(3 战胜 4)P(2 战胜 3) + P(2 战胜 1)P(4 战胜 3)P(2 战胜 4) |
P(3 胜) | = P(1 战胜 2)P(3 战胜 4)P(3 战胜 1) + P(2 战胜 1)P(3 战胜 4)P(3 战胜 2) |
P(4 胜) | = P(2 战胜 1)P(4 战胜 3)P(4 战胜 2) + P(1 战胜 2)P(4 战胜 3)P(4 战胜 1) |
容易看出,一部分是重复的,如:在 P(1 胜)中的P(1 战胜 2)。
这时,我们毫不惊奇地发现:可以维护它在战胜对手后,对上其他对手的胜率
即:他的胜率=他胜对手1的胜率对手1胜对手2的胜率+他胜对手2的胜率对手2胜对手1的胜率。
代码如下:
#include<iostream>
#include<string.h>
using namespace std;
double p[130][130][8],dp[130],wh=1;//p[i][j][k]指i到第k轮统计时对区块j中对手的胜率
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,m,c=1;
cin>>n;
q=m=1<<n;
for(int i=1;i<=m;i++)for(int j=1;j<=m;j++)cin>>p[i][j][0];
memset(dp,1.0,sizeof(dp));
q>>=1;
for(int i=1;i<n;q>>1,c<<1,i++)for(int j=1;j<=q;j++)for(int k=1;k<=c;k++){
dp[(2*j-2)*c+k]*=p[(2*j-2)*c+k][2*j][i-1];
dp[(2*j-1)*c+k]*=p[(2*j-1)*c+k][2*j-1][i-1];
for(int u=1;u<=m;u++)p[u][j][i]+=dp[(2*j-2)*c+k]*p[u][2*j-1][i-1]+dp[(2*j-1)*c+k]*p[u][2*j][i-1];
}
for(int i=2;i<=m;i++)if(i>p[wh][1][n-1])wh=i;
cout<<wh;
}