HDU 4336状压或者容斥原理

题意: 有N(1<=N<=20)张卡片,每包中含有这些卡片的概率为  p1,p2,pn

每包至多一张卡片,可能没有卡片。求需要买多少包才能拿到所有的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;
}

(2)状压DP解决:

以下是队友的思路:第一次做状压DP,看的是队友怎么分析的,然后现在终于理解了。

于是包中没有卡片的概率就是

pno=1i=1npi

用20个二进制位来表示现在拿到了哪些卡片。卡片全拿到(全为1)的状态显然是只需要拿0次。接下来我们枚举状态(每次减1),对于每种状态考虑此时买一包的情况。

我们有

Ex=nothavepiEi+(havepi+pno)Ex+1

整理得

Ex=nothavepiEi+11havepipno

如果买的是之前有的,那么状态不改变,同时将概率加到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;
}


你可能感兴趣的:(HDU 4336状压或者容斥原理)