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\) 不大的时候, 用二进制数压缩
注意不需要额外在计算第几条鱼上加一层循环

浙公网安备 33010602011771号