Codeforces Beta Round #16 E. Fish (状压dp)(概率dp)

Codeforces Beta Round #16 (Div. 2 Only) E. Fish

题目链接:## 点击打开链接

题意:##

\(n\) 条鱼,每两条鱼相遇都会有其中一只吃掉对方,现在给你一个 \(n * n\)的矩阵,表示 \(i\) 吃掉 \(j\) 的概率,最后问你每条鱼存活的概率。

题解:##

最多有 \(18\) 条鱼,吃掉的概率都不一样,可以用状态压缩,设\(dp[1<<n]\)种状态,最多有 \(1<<18\) 种状态。
$ dp[i]$ 表示当前鱼的状态为 \(i\) 时的概率。
那么,\(dp( i 吃掉 j ) = dp( i 和 j 同时存在) * p( i 战胜 j )的概率 * prob(i 和 j 相遇)的概率\)

f[i - (1<<k)] += f[i] * prob[j][k] * 1.0 / (cnt * (cnt - 1) / 2) ;// k 被吃掉 
f[i - (1<<j)] += f[i] * prob[k][j] * 1.0 / (cnt * (cnt - 1) / 2); // j 被吃掉 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
double prob[18][18];
double f[1<<18];
int cnt;
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
    	for(int j=0;j<n;j++)
    	{
    		cin>>prob[i][j];
		}
	}
	f[(1<<n)-1] = 1;//所有鱼都在,初始化概率都是 1 
	for(int i=(1<<n)-1;i>0;--i)//遍历所有状态 
	{
		cnt = 0;
		for(int j=0;j<n;j++) //遍历获胜的鱼的编号
		{
			if(i & (1<<j))//j号鱼还活着
			{
				cnt++;
			}
		}
		for(int j=0;j<n;j++)//遍历鱼j要吃掉的k号鱼  
		{
			if((i&(1<<j))==0)continue;//j号鱼不存活 
			
			for(int k=j+1;k<n;k++) 
			{
				if((i&(1<<k))==0)continue;//k号鱼不存活 
				//f( j 吃掉 k ) = f( j 和 k 同时存在) * f( j 战胜k) * f( j 和 k 相遇)
				//1<<k : 第k位的1一定存在 
				f[i - (1<<k)] += f[i] * prob[j][k] * 1.0 / (cnt * (cnt - 1) / 2);//k被吃掉 
				f[i - (1<<j)] += f[i] * prob[k][j] * 1.0 / (cnt * (cnt - 1) / 2);//j被吃掉 
			}
		}
	}
	
	for(int i=0;i<n-1;i++)
	{
		printf("%.6f ",f[1<<i]);//分别输出只有第 i 条鱼存活的概率
	}
	printf("%.6f\n",f[1<<(n-1)]);
    return 0;
}
posted @ 2017-10-20 16:56  LzyRapx  阅读(241)  评论(0编辑  收藏  举报