Loading

Fish

题目链接

Fish

算法

状压dp 维护余下鱼的存在集合

代码

#include <bits/stdc++.h>
const int MAXN = 20;
const int MAXSize = (1 << 18);

int n;

double P_eat[MAXN][MAXN]; //第 i 条鱼 吃 第 j 条鱼的概率
double Sum_eat[MAXN]; //第 i 条鱼被吃的概率总和

/*一个二进制的 1 的个数*/
int calc(int x)
{
    int Sum = 0;
    while(x)
    {
        if(x & 1)
            Sum++;
        x /= 2;
    }

    return Sum;
}

double Brute_Calc(int state, int Num, int LiveFish)
{
    double Ans = 0.0;
    int NowFish = 1;
    while(state)
    {
        if(state & 1)
        {
            Ans += P_eat[NowFish][LiveFish];
        }
        NowFish++;
        state >>= 1;
    }

    return Ans;
}

double dp[MAXSize];
void solve()
{
    /*计算每一条鱼最后存活的概率*/
    memset(dp, 0, sizeof(dp));
    dp[(1 << n) - 1] = 1.0;
    for (int j = (1 << n) - 2; j >= 0; j--)
    {
        int CanLive = (1 << n) - j - 1;
        int k = 1;
        while(CanLive)
        {
            if(CanLive & 1)
            {
                int NowFishNum = calc(j); // 当前鱼的数量

                double Sum = Brute_Calc(j, NowFishNum, k);

                dp[j] += dp[j + (1 << (k - 1))] * Sum * (2.0 / ((NowFishNum + 1) * (NowFishNum)));
            }

            CanLive /= 2;
            k++;
        }
    }

    for (int i = 1; i <= n; i++)
    {
        printf("%lf ", dp[1 << (i - 1)]);
    }
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            scanf("%lf", &P_eat[i][j]);
            Sum_eat[j] += P_eat[i][j];
        }
    }


    solve();

    return 0;
}

总结

状压dp常用于 \(N\) 不大的时候, 用二进制数压缩
注意不需要额外在计算第几条鱼上加一层循环

posted @ 2024-09-29 19:57  Yorg  阅读(18)  评论(0)    收藏  举报