首页 > 代码库 > poj3071(概率DP)

poj3071(概率DP)

题意:淘汰赛制,2^n(n<=7)个队员.给出相互PK的输赢概率矩阵。问谁最有可能赢到最后。


解法:ans[i][j]表示第i个队员第j轮胜出的概率。赢到最后需要进行n场比赛。算出每个人赢到最后的ans[i][n]。写出序号的二进制发现一个规律,两个队员i、j如果碰到,那么一定是在第get(i,j)场比赛碰到的。get(i,j)计算的是i和j二进制不同的最高位,这个规律也比较明显。

代码:

/******************************************************
* author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
//freopen ("in.txt" , "r" , stdin);
using namespace std;

#define eps 1e-8
const double pi=acos(-1.0);
typedef long long LL;
const int Max=500;
const int INF=1000000007;

int n;
double num[Max][Max];
bool rem[Max][Max];
double ans[Max][10];
int get(int i,int j)
{
    for(int k=n-1;k>=0;k--)
    {
        if((i&(1<<k))^(j&(1<<k)))
            return k;
    }
}
int main()
{
    while(scanf("%d",&n)==1)
    {
        memset(ans,0,sizeof ans);
         memset(rem,0,sizeof rem);
        if(n==-1)
            break;
        for(int i=0; i<(1<<n); i++)
            for(int j=0; j<(1<<n); j++)
                scanf("%lf",num[i]+j);
        for(int i=0;i<(1<<n);i++)
            ans[i][0]=1.0;
        for(int k=0;k<n;k++)
        {
            for(int i=0;i<(1<<n);i++)
                for(int j=i+1;j<(1<<n);j++)
            {
                int t=get(i,j);
                if(t!=k)continue;
                ans[i][k+1]+=ans[j][k]*ans[i][k]*num[i][j];
                ans[j][k+1]+=ans[i][k]*ans[j][k]*num[j][i];
            }
        }
        double t=0;
        double sum=0;
        int out=0;
        for(int i=0;i<(1<<n);i++)
        {
            if(t<ans[i][n])
            {
                t=ans[i][n];
                out=i;
            }
        }
        cout<<out+1<<endl;
    }
    return 0;
}