poj 3071 【概率dp】

题目链接:poj 3071 Football


题意:有2^n只足球队,已知你两两足球队间的胜率p[i][j](足球队i赢足球队j的概率),赛制为单轮淘汰制并且每轮中剩余队伍序号1与2对战,3与4对战,5与6对战...问n轮过后哪只足球队的胜率最大。


题解:设dp[i][j]为第i轮第j只队伍获胜的概率,

转移方程如下:

dp[i][j] += dp[i-1][j]*p[j][k]*dp[i-1][k]

k为第i轮可能与j对战的球队

这里k与i和j是存在关系的,可以写下可能的对战序列进行观察,这里取八只队伍:

第一轮 1:(2) 2:(1) 3:(4) 4:(3) 5:(6) 6:(5) 7:(8) 8:(7)

第二轮 1:(3,4) 2:(3,4) 3:(1,2) 4:(1,2) 5:(7,8) 6:(7,8) 7:(5,6) 8:(5,6)

第三轮 1:(5,6,7,8) 2:(5,6,7,8) 3:(5,6,7,8) 4:(5,6,7,8) 5:(1,2,3,4) 6:(1,2,3,4) 7:(1,2,3,4) 8:(1,2,3,4)

从上面就可以找到规律确定k的范围


#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include<string.h>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<time.h>
#include<sstream>

using namespace std;
#define MAX_N 100005
#define inf 0x3f3f3f3f
#define LL long  long
#define ull unsigned long long
const LL INF = 1e18;
const double eps = 1e-8;
//const int mod = 1e9+7;
//const double pi = acos(-1);
typedef pair<int, int>P;

double p[1<<8][1<<8];
double dp[10][1<<8];
int pow2(int k)
{
    int ans = 1;
    while(k) {
        k--;
        ans *= 2;
    }
    return ans;
}
int cal(int a, int b)
{
    return (b/a)+1;
}
int main()
{
    int n;
    while(cin >> n && n!=-1) {
        for(int i=0; i<(1<<n); i++)
            for(int j=0; j<(1<<n); j++)
                scanf("%lf", &p[i][j]);
        memset(dp, 0, sizeof(dp));
        for(int i=0; i<(1<<n); i++)
            dp[0][i] = 1;
        for(int i=1; i<=n; i++) {
            for(int j=0; j<(1<<n); j++) {
                int m = pow2(i-1);
                int pos = cal(2*m, j);
                int mid = (2*pos-1)*m;
                int s, e;
                if(j < mid) {
                    s = mid;
                    e = pos*m*2;
                }
                else {
                    s = (pos-1)*m*2;
                    e = mid;
                }
                //printf("%d %d %d %d\n", i, j, s, e);
                for(int k=s; k<e; k++) {
                    dp[i][j] += dp[i-1][j]*p[j][k]*dp[i-1][k];
                }
            }
            //puts("");
        }
        int idx = 0;
        for(int i=0; i<(1<<n); i++) {
            //printf("%.3lf ", dp[n][i]);
            if(dp[n][i] > dp[n][idx])
                idx = i;
        }
        //puts("");
        cout << idx+1 << endl;
    }
}

代码写的略渣了点。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值