●POJ 2794 Double Patience

题链:

http://poj.org/problem?id=2794
题解:

状压DP,概率
9元组表示每一堆还剩几张牌。可以用5进制状压,共5^9=1953124个状态。
令P(S)表示S这个状态被取完的概率。

假设当前状态为S,可以有三种取法,分别对应转移到_S1,_S2,_S3三个更小的状态。
那么由全概率公式:
如果_S1状态为前提条件,那么S就有1/3的概率转移到_S1
同理_S2,_S3。所以得出:
P(S)=P(S|_S1)*P(_S1)+P(S|_S2)*P(_S2)+P(S|_S3)*P(_S3)
由于P(S|_S1=)P(S|_S2)=P(S|_S3)=1/3
所以P(S)=(P(_S1)+P(_S2)+P(_S3))/3

即每个状态的概率为其后继状态的平均值。


代码:

 

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
char card[10][5];
bool vis[2000000];
double dp[2000000];
int code(int *a){
	static int s; s=0;
	for(int i=9;i>=1;i--)
		s=s*5+a[i];
	return s;
}
void decode(int s,int *a){
	for(int i=1;i<=9;i++)
		a[i]=s%5,s/=5;
}
double DP(int s){
	if(vis[s]) return dp[s];
	vis[s]=1;
	int a[10],cnt=0; decode(s,a);
	for(int i=1;i<=9;i++)
		for(int j=i+1;j<=9;j++){
			if(!a[i]||!a[j]||card[i][a[i]]!=card[j][a[j]]) continue;
			a[i]--; a[j]--; cnt++;
			int _s=code(a);
			dp[s]+=DP(_s);
			a[i]++; a[j]++;
		}
	if(cnt) dp[s]/=cnt;
	return dp[s];
}
int main(){
	static char S[5];
	for(int i=1;i<=9;i++)
		for(int j=1;j<=4;j++)
			scanf("%s",S),card[i][j]=S[0];
	vis[0]=1; dp[0]=1;
	printf("%.6lf\n",DP(1953124));
	return 0;
}

 

  

 

posted @ 2018-03-10 20:48  *ZJ  阅读(95)  评论(0编辑  收藏  举报