。每包至多一张卡片,可能没有卡片。求需要买多少包才能拿到所有的N张卡片,求次数的期望。
思路:(1)先用容斥原理解决:n<=20,二进制表示取不取的状态,1取0不取,故共有1<<n种状态。然后枚举每种状态,然后枚举每个卡片是否可以取……
#include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <list> #include <queue> #include <string> #include <cstring> #include <map> #define PI acos(-1.0) #define mem(a,b) memset(a,b,sizeof(a)) #define sca(a) scanf("%d",&a) #define pri(a) printf("%d\n",a) #define MM 500002 #define MN 1002 #define INF 168430090 using namespace std; typedef long long ll; int main() { int n; while(cin>>n) { int i,j,t; double ans,sum=0,p[21]; for(i=0;i<n;i++) cin>>p[i]; for(i=1;i<(1<<n);i++) //枚举每种状态,i化为二进制就知道其中原理了 { ans=0; t=0; for(j=0;j<n;j++) if(i&(1<<j)) {ans+=p[j];t++;} //j枚举每种卡片是否同i中对应的位置也是1,是则取 if(t&1) sum+=1/ans; //容斥原理中奇加偶减 else sum-=1/ans; } printf("%.4lf\n",sum); } return 0; }
以下是队友的思路:第一次做状压DP,看的是队友怎么分析的,然后现在终于理解了。
于是包中没有卡片的概率就是
用20个二进制位来表示现在拿到了哪些卡片。卡片全拿到(全为1)的状态显然是只需要拿0次。接下来我们枚举状态(每次减1),对于每种状态考虑此时买一包的情况。
我们有
整理得
如果买的是之前有的,那么状态不改变,同时将概率加到px里。如果买的是之前没有的,那就把那种情况发生的概率乘以那时状态的期望(一定是计算过的,因为比此时状态大的状态必然之前算过)加到sum里。最后dp[i]=期望次数+1/(1-px-没有卡片的概率)
#include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <list> #include <queue> #include <string> #include <cstring> #include <map> #define PI acos(-1.0) #define mem(a,b) memset(a,b,sizeof(a)) #define sca(a) scanf("%d",&a) #define pri(a) printf("%d\n",a) #define MM 500002 #define MN 1002 #define INF 168430090 using namespace std; typedef long long ll; double dp[1<<21],p[21]; int main() { int n; while(cin>>n) { int i,j; double s=0; for(i=0;i<n;i++) cin>>p[i],s+=p[i]; s=1-s; dp[(1<<n)-1]=0;//全部为1的情况为0 for(i=(1<<n)-2;i>=0;i--) //从二进制中1最多的递推到1少的,下面用或真是精辟啊 { double sum=0,px=0; for(j=0;j<n;j++) if((i|(1<<j))!=i) sum+=p[j]*dp[i|(1<<j)]; else px+=p[j]; dp[i]=(sum+1)/(1-px-s); } printf("%.4lf\n",dp[0]); } return 0; }