1. 程式人生 > >codeforces 16E 概率+狀壓dp

codeforces 16E 概率+狀壓dp

思路:

n為18.每一為為0則是魚死了,1則是活著。

初始狀態:全活著的概率為1

當前狀態的魚j殺死魚k的概率,相遇的概率乘以j殺k的概率,累加至新狀態即可。


#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <stack>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <stdlib.h>
#include <iomanip>
#include <fstream>

using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define maxn 105
#define MOD 1000000007
#define mem(a , b) memset(a , b , sizeof(a))
#define LL long long
#define ULL unsigned long long
#define FOR(i , n) for(int i = 1 ;  i<= n ; i ++)
typedef pair<int , int> pii;
#define INF 100000000
int n;
double a[maxn][maxn];
double dp[1<<18];

int main()
{
    while(scanf("%d" , &n) != EOF)
    {
        for(int i = 0 ; i < n ; i ++)
        {
            for(int j = 0 ; j < n ; j ++)
            {
                scanf("%lf" , &a[i][j]);
                //cout << a[i][j] << endl;
            }
        }
        mem(dp , 0);
        dp[(1<<n) - 1] = 1;
        for(int i = (1<<n) - 1 ; i >= 1 ; i --)
        {
            int num = 0 , tmp = i;
            while(tmp != 0)
            {
                if(tmp & 1) num ++;
                tmp >>= 1;
            }
            if(num == 1) continue;
            double ch = 2.0 * dp[i] / num / (num-1);
            for(int j = 0 ; j < n ; j ++)
            {
                if(i & ( 1 << j))
                {
                    for(int k = 0 ; k < n ; k ++)
                    {
                        if(i & ( 1 << k))
                        {
                            dp[i^(1<<k)] += ch * a[j][k];
                        }
                    }
                }
            }
        }

        for(int i = 0 ; i < n ; i ++)
        {
            printf("%.6lf" , dp[(1 << i)]);
            if(i != n-1) printf(" ");
        }
        cout <<endl;
    }
    return 0;
}