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;
}
posted @ 2024-09-02 19:03  yzc_is_SadBee  阅读(6)  评论(0编辑  收藏  举报