51nod 1943 联通期望 【状压DP】

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/C20181220_xiang_m_y/article/details/88658611

题面:

在一片大海上有n个岛屿,规划建设m座桥,第i座桥的成本为zi,但由于海怪的存在,第i座桥有pi的概率不能建造。

求在让岛屿尽量联通的情况下,期望最小成本为多少。
尽量联通:在对每座桥确定能否建造的情况下,对于任意两个岛屿,如果存在一种建桥方案使得它们联通,那么它们必须联通。
n≤14,m≤n(n−1)2

题目分析:

装呀DP?
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
似乎还是很显然吧。。
对于 H H ,可以直接计算前 i i 条边中任意点集的所有p的乘积
PPT中的 H ( i , S , T ) H(i,S,T) 就可以表示为 H [ S T ] / H [ S ] / H [ T ] H[S|T]/H[S]/H[T]

Code:

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define maxn 15
#define rg register
using namespace std;
template<class T>inline void read(T &a){
    char c;while(!isdigit(c=getchar()));
    for(a=c-'0';isdigit(c=getchar());a=a*10+c-'0');
}
struct node{
    int u,v,z;double p;
    bool operator < (const node &B)const{return z<B.z;}
}e[maxn*maxn];
int n,m;
double ans,f[1<<maxn],h[1<<maxn],tmp;
int main()
{
    read(n),read(m);
    for(int i=1;i<=m;i++) read(e[i].u),read(e[i].v),read(e[i].z),scanf("%lf",&e[i].p);
    sort(e+1,e+1+m);
    for(int i=0;i<(1<<n);i++) h[i]=1;
    for(int i=0;i<n;i++) f[1<<i]=1;
    for(int k=1;k<=m;k++){
        rg int x=1<<(e[k].u-1),y=1<<(e[k].v-1),xy=x|y;
        rg int s=((1<<n)-1)^xy;
        for(rg int i=s;;i=(i-1)&s) if(f[i|x]){//有很多状态都是0
            rg int t=s^i;
            for(rg int j=t;;j=(j-1)&t) if(f[j|y]){
                f[i|j|xy]+=(tmp=(1-e[k].p)*f[i|x]*f[j|y]/h[i|j|xy]*h[i|x]*h[j|y]);
                ans+=e[k].z*tmp;
                if(!j) break;
            }
            if(!i) break;//注意这里的集合都可以为空
        }
        for(rg int t=s;;t=(t-1)&s){
            f[t|x]*=e[k].p;
            f[t|y]*=e[k].p;
            h[t|xy]*=e[k].p;
            if(!t) break;
        }
    }
    printf("%.6f",ans);
}

猜你喜欢

转载自blog.csdn.net/C20181220_xiang_m_y/article/details/88658611