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;
}

转载于:https://www.cnblogs.com/LzyRapx/p/7700342.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值