【不知出处】炸弹拆除 网络流 费用流

来源:互联网 发布:扎克拉文体测数据 手掌 编辑:程序博客网 时间:2024/06/09 16:45

题目描述

  连锁炸弹是恐怖分子最近开始使用的一种威力巨大的爆炸物。其复杂的结构使拆除它的难度大大增加了。
  一个连锁炸弹由m个引爆装置和n枚炸弹组成。每个引爆装置中有n条信号线分别与这n枚炸弹相连(1号线连接炸弹1,2号线连接炸弹2,……)。与一枚炸弹相连的m条信号线中只有一条是“安全线”——剪断后可以拆除炸弹,而剪断其它信号线则引爆炸弹
  专业的技术人员将给出一个m×n的表格。其中第i行第j列显示了引爆装置i与炸弹j连接的信号线是“安全线”的可能性Pi,j(Pi,j ∈(0,1)),并且已知每个引爆装置上的“安全线”数目不超过k 。技术人员的分析结果是绝对值得信任的。
[任务]:
  政府的安全部门常常雇佣一些程序员去设计解决突发情况的程序。其中一项任务正是提高排除连锁炸弹的成功率。成功的拆除一个连锁炸弹,必须切断与炸弹相连所有n条“安全线”。现在,请设计一个程序,求出应剪断哪n条信号线,才能使拆除所有炸弹的可能性 ∏ Pi,j(即所有剪断的信号线Pi,j的乘积)最大。

数据范围

m,n,k<=50,k<=n

样例输入

4 5 2
0.95 0.20 0.57 0.48 0.50
0.56 0.88 0.42 0.80 0.90
0.70 0.65 0.42 0.60 0.87
0.91 0.80 0.72 0.44 0.20

样例输出

0.4189

解题思路

源点向装置连边,权值为k,费用为1
装置向炸弹连边,权值为1,费用为pij
炸弹向汇点连边,权值为1,费用为1
AC!
但是!spfa不能用乘法连接,,,所以这除了并不能过样例,虽然可以水对几组
源点向装置连边,权值为k,费用为0
装置向炸弹连边,权值为1,费用为logpij
炸弹向汇点连边,权值为1,费用为0
答案就是exp(答案)A.A

代码

#include <algorithm>#include <iostream>#include <cstring>#include <cstdlib>#include <cstdio>#include <cmath>#include <queue>#define Maxn 233333#define Maxe 233333using namespace std;inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}int u[Maxn],d[Maxn],pre[Maxn],preto[Maxn],vis[Maxn],h[Maxn],cnt,S,T,n,m,kk,s;double pp[55][55],dis[Maxn];struct node{int to,next,v;double k;int pair;}e[Maxe];void AddEdge(int x,int y,int v,double k,int pair){e[cnt].to=y;e[cnt].next=h[x];e[cnt].v=v;e[cnt].k=k;e[cnt].pair=pair;h[x]=cnt;}void AddEdge(int x,int y,int v,double k){AddEdge(x,y,v,k,++cnt+1);AddEdge(y,x,0,-k,++cnt-1);}bool SPFA(){    queue<int>Q;    for(int i=S;i<=T;i++)dis[i]=-2147483647;//这里要是最小值    memset(vis,0,sizeof(vis));    memset(pre,0,sizeof(pre));    memset(preto,0,sizeof(preto));    dis[S]=0;    vis[S]=1;    Q.push(S);    while(Q.size()){        int x=Q.front();        Q.pop();        vis[x]=false;        for(int p=h[x];p;p=e[p].next){            int y=e[p].to;            if(e[p].v&&dis[y]<dis[x]+e[p].k){//这里是小于号                pre[y]=p;                preto[y]=x;                dis[y]=dis[x]+e[p].k;                if(!vis[y])Q.push(y);            }        }    }    return dis[T]!=(-2147483647);}double Adjust(){    int flow=1<<30;    for(int p=T;p!=S;p=preto[p])        flow=min(flow,e[pre[p]].v);    for(int p=T;p!=S;p=preto[p]){        e[pre[p]].v-=flow;        e[e[pre[p]].pair].v+=flow;    }    return dis[T]*flow;}double Solve(){    double Ans=0,tmp;    while(SPFA())Ans+=tmp=Adjust();    return Ans;}void Init(){    m=Getint(),n=Getint(),kk=Getint();    for(int i=1;i<=m;i++)        for(int j=1;j<=n;j++)            scanf("%lf",&pp[i][j]);    S=0,T=n+m+1;    for(int i=1;i<=m;i++)        AddEdge(S,i,kk,0);    for(int i=1;i<=n;i++)        AddEdge(i+m,T,1,0);    for(int i=1;i<=m;i++)        for(int j=1;j<=n;j++)            AddEdge(i,j+m,1,log(pp[i][j]));//加一个log}int main(){    Init();    printf("%.4lf",exp(Solve()));//加一个exp    return 0;}
0 0