1. 程式人生 > 其它 >Football(概率dp)

Football(概率dp)

題目連結

題目大意

  有一場足球賽,一共有\(n\)輪,上一輪勝出的隊伍與這一輪與其相鄰的隊伍比賽(1和2,3和4) 給你任意兩個隊比賽會獲勝的概率,求最後那個隊獲勝的概率最大。

解題思路

  第一輪兩個隊之間有一個會獲勝,第二輪四個隊之間有一個會獲勝,第三輪8個隊之間有一個會獲勝...第一輪分成人數為1的小組,第二輪分成人數為2的小組,第三輪分成人數為3的小組...發現每輪比賽都是第1組和第2組打,第3組和第4組打。
  然後就是計算概率了,可以發現每輪每個隊的獲勝概率有遞推關係,設\(dp[i][j]\)表示第\(i\)隊第\(j\)輪勝出,那麼第\(i\)隊第\(j+1\)輪勝出的概率就是和相鄰組打所有勝出情況的概率之和。即\(dp[i][j+1] = \sum {dp[i][j]\times p[i][k]\times dp[k][j]}\)

.

const int maxn = 1e3+10;
const int maxm = 1e6+10;
double p[maxn][maxn], dp[maxn][maxn];
int main() {
    //IOS;
    int t; 
    while(cin >> t && (~t)) {
        int n = 1<<t;
        for (int i = 0; i<n; ++i)
            for (int j = 0; j<n; ++j)
                scanf("%lf", &p[i][j]);
        for (int i = 0; i<n; ++i) dp[i][0] = 1;
        for (int i = 0; i<t; ++i) {
            int sz = 1<<i;
            //cout << "_____________i_______________" << endl;
            for (int j = 0; j<n; ++j) {
                //cout << "-----j-----" << endl;
                int now = j/sz;
                double sum = 0;
                if (now&1) {
                    for (int k = (now-1)*sz; k<now*sz; ++k) {
                        sum += dp[j][i]*p[j][k]*dp[k][i];
                        //cout << j << ' ' << k << endl;
                    }
                }
                else {
                    for (int k = (now+1)*sz; k<(now+2)*sz; ++k) {
                        sum += dp[j][i]*p[j][k]*dp[k][i];
                        //cout << j << ' ' << k << endl;
                    }
                }
                dp[j][i+1] = sum;
                //cout << sum << endl;
            }
        }
        int ans = 0;
        for (int i = 0; i<n; ++i)
            if (dp[ans][t]<dp[i][t]) ans = i;
        cout << ans+1 << endl;
    }
    return 0;
}