详细的题目大意与解析大家参考一下kuangbin的文章。
这边说一下自己对于kuangbin代码以及容斥原理位元素枚举的理解与解释,希望对大家有所帮助。
状态DP AC代码:状态压缩的思想我就不赘述了,我也只是略懂,这边仅仅分析一下状态方程
由于量比较多,我这边有的便用文字代替,有利于描述。
dp[i]表示i状态达到满状态(即收集满n个物品,以下称满状态)所需要的期望。
那么i状态当中收集了x的物品,剩余n-x个物品没有收集
那么dp[i]=p*dp[i]+p2*dp[i2]+1;
这边解释一下上面的变量:
p表示的是假如下一次抽到的物品是已经搜集过的物品被抽到的概率之和,至于为什么要这样子,有概率DP基础的应该知道吧?状态分解,事件之和。
p2表示的是抽到没有收集过物品的概率,已经加上该物品之后的状态要达到满状态的期望,这边少了一个累加,所有没有收集的累加。依然依据的是状态的分解和事件之和。
假如有问题的话,欢迎评论指教。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
double dp[1 << 22];
double p[22];
int main()
{
int n;
while (cin >> n)
{
double op = 0;
for (int i = 0; i <n; i++)
{
scanf("%lf", &p[i]);
op += p[i];
}
op = 1 - op;
dp[(1 << n) - 1] = 0;
for (int i = (1 << n) - 2; i >= 0; i--)
{
double x = 0, sum = 1;
for (int j = 0; j < n;j++)
if (i&(1 << j)) x += p[j];
else sum += p[j] * dp[i|(1 << j)];
dp[i] = sum / (1 - op - x);
}
printf("%.5lf\n", dp[0]);
}
}
容斥原理应用:位运算枚举
这边可能你需要百度一下容斥原理是怎么一个东西,再回来看我的解释会比较清楚,因为容斥原理我也不知道怎么讲才清楚,这边提供一个别人推荐的文章。容斥原理
好了,现在你可能已经懂了什么是容斥原理。
那么这边我以n=3为例。并且按照状态压缩来讲解。
我现在是要得到111的
那么1/p1(p1表示的是事件1发生的概率)表示的是1发生的概率,这边包括001,011,111,101
同理,1/p2包括的是010,011,111,110
1/p3:100,101,111,110
将三个相加,所得到的便是状态001,010,100,011*2,101*2,110*2,111*3这些状态对应的期望.我们需要的是111状态,所以需要想办法减去其他的
1/(p2+p1)包括,011,010,001,111,110,101
1/(p2+p3)包括110,100,010,111,101,011
1/(p3+p1)包括101,001,100,111,011,110
1/(p1+p2+p3)包括001,010,100,110,011,101,111
根据容斥原理,减去上面三个,得到:(全是负的)001,010,100,110,011,101
所以最后再加上一个1/(p1+p2+p3)即得到111状态对应的期望。
1/p对应的是期望,希望大家好好理解,我也是看了很久,有问题的欢迎跟我交流哈。QQ:417033420
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
double p[22];
int main()
{
int n;
while (scanf("%d", &n) == 1)
{
for (int i = 0; i<n; i++)scanf("%lf", &p[i]);
double ans = 0;
for (int i = 1; i<(1 << n); i++)
{
int cnt = 0;
double sum = 0;
for (int j = 0; j<n; j++)
if (i&(1 << j))
{
sum += p[j];
cnt++;
}
if (cnt & 1)ans += 1.0 / sum;
else ans -= 1.0 / sum;
}
printf("%.5lf\n", ans);
}
return 0;
}