GYM 100883 A.Random Fightings (状压DP)

来源:互联网 发布:ubuntu 火狐浏览器 编辑:程序博客网 时间:2024/06/06 13:23

Description
n个人打架,每两个人打架的概率是相同的,且每次只会有两个人打架,i打败j的概率是A[i][j],一个人被打败就没法打架了,问最后第i个人获胜的概率是多少
Input
第一行一整数T表示用例组数,每组用例首先输入一整数n表示人数,之后一个n*n矩阵A,A[i][j]表示i打败j的概率
(1<=n<=20,0<=a[i][j]<=1)
Output
对于每组用例,输出n个实数表示第i个人最终获胜的概率
Sample Input
2
1
0.0
2
0.0 0.5
0.5 0.0
Sample Output
Case 1: 1.000000
Case 2: 0.500000 0.500000
Solution
用mask表示当前剩余人数的状态,设人数为res,则这res个人中会有两个人要打架,比如i打败j,那么有dp[mask-(1 << j)]+=dp[mask]*A[i][j]/C(res,2),初始状态dp[(1 << n)-1]=1表示n个人都在,答案就是dp[1 << i]
Code

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<vector>#include<queue>#include<map>#include<set>#include<ctime>using namespace std;typedef long long ll;#define INF 0x3f3f3f3f#define maxn 1111111double a[22][22],dp[maxn];int T,n,b[22],res;int main(){    scanf("%d",&T);    for(int Case=1;Case<=T;Case++)    {        scanf("%d",&n);        for(int i=0;i<n;i++)            for(int j=0;j<n;j++)                scanf("%lf",&a[i][j]);        memset(dp,0,sizeof(dp));        int N=1<<n;        dp[N-1]=1.0;        for(int i=N-1;i>=0;i--)            if(dp[i])            {                res=0;                for(int j=0;j<n;j++)                    if(i&(1<<j))b[res++]=j;                for(int j=0;j<res;j++)                    for(int k=0;k<res;k++)                        if(j!=k)                            dp[i-(1<<b[k])]+=a[b[j]][b[k]]*dp[i]/(res*(res-1)/2);            }        printf("Case %d:",Case);        for(int i=0;i<n;i++)printf(" %.6f",dp[1<<i]);        printf("\n");    }    return 0;}
0 0
原创粉丝点击