HDU 5988 Coding Contest(费用流+浮点数)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5988
题目大意:
给定n个点,m条有向边,每个点是一个吃饭的地方,每个人一盒饭。每个点有S个人,有B盒饭。每条边只能被走c次,每条边上都有电线,
第一个人通过的时候,不会破坏电线,从第二个人开始,每次都有概率p破坏掉电线。使得每个人都能吃饭,求最小破坏电线的概率。
解题思路:
题目要求我们求最小破坏电线的概率,就是一个最小乘积问题,加上log可以将其转变为加法,那样就可以使用费用刘来解决了。
按以下方式建图:
①源点st向第i个人建边,流量为S。
②第i个人向汇点建边,流量为B。
③u->v连边,流量为c,花费为-log(1-p)。
然后跑费用流,1-exp(-cost)即为答案。
代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #include<vector> 8 #define LL long long 9 #define pii pair<double,int> 10 #define pll pair<long long,long long> 11 #define rep(i,a,b) for(int i=a;i<=b;i++) 12 #define per(i,a,b) for(int i=a;i>=b;i--) 13 #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); 14 #define bug cout<<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"<<endl; 15 #define bugc(_) cout << (#_) << " = " << (_) << endl; 16 using namespace std; 17 const double eps=1e-8; 18 const int N=1e2+5; 19 const int M=1e5+5; 20 const int INF=0x3f3f3f3f; 21 22 struct node{ 23 int to,next,flow; 24 double cost; 25 }edge[M*2]; 26 27 int cnt,st,en,n,m; 28 int head[N],pre[N]; 29 double dis[N];//dis[i]表示到dis[i]为止不破坏电线的最大概率 30 bool vis[N]; 31 32 int sgn(double x) { return x < -eps? -1: x > eps; } 33 34 void init(){ 35 cnt=2; 36 memset(head,0,sizeof(head)); 37 } 38 39 void link(int u,int v,int flow,double cost){ 40 edge[cnt]=node{v,head[u],flow,cost}; 41 head[u]=cnt++; 42 edge[cnt]=node{u,head[v],0,-cost}; 43 head[v]=cnt++; 44 } 45 46 bool spfa() { 47 memset(pre,0,sizeof(pre)); 48 memset(vis,false,sizeof(vis)); 49 for(int i=st;i<=en;i++) dis[i]=INF; 50 dis[st]=0; 51 queue<int>q; 52 q.push(st); 53 while(!q.empty()){ 54 int u=q.front(); 55 q.pop(); 56 vis[u]=false; 57 for(int i=head[u];i;i=edge[i].next){ 58 node t=edge[i]; 59 if(t.flow&&dis[t.to]>dis[u]+t.cost+eps){ 60 dis[t.to]=dis[u]+t.cost; 61 pre[t.to]=i; 62 if(!vis[t.to]){ 63 vis[t.to]=true; 64 q.push(t.to); 65 } 66 } 67 } 68 } 69 if(dis[en]==INF) 70 return false; 71 return true; 72 } 73 74 void mcmf(int &flow,double &cost){ 75 while(spfa()){ 76 int mmin=INF; 77 for(int i=pre[en];i;i=pre[edge[i^1].to]){ 78 mmin=min(mmin,edge[i].flow); 79 } 80 for(int i=pre[en];i;i=pre[edge[i^1].to]){ 81 edge[i].flow-=mmin; 82 edge[i^1].flow+=mmin; 83 cost+=edge[i].cost*mmin; 84 } 85 flow+=mmin; 86 } 87 } 88 89 int main(){ 90 int T; 91 scanf("%d",&T); 92 while(T--){ 93 init(); 94 int n,m; 95 scanf("%d%d",&n,&m); 96 st=0,en=n+1; 97 for(int i=1;i<=n;i++){ 98 int s,b; 99 scanf("%d%d",&s,&b); 100 if(s-b>0) link(st,i,s-b,0); 101 if(s-b<0) link(i,en,b-s,0); 102 } 103 for(int i=1;i<=m;i++){ 104 int u,v,flow; 105 double p; 106 scanf("%d%d%d%lf",&u,&v,&flow,&p); 107 p=-log(1-p); 108 if(flow>0) link(u,v,1,0); 109 if(flow>1) link(u,v,flow-1,p); 110 } 111 int flow=0; 112 double cost=0; 113 mcmf(flow,cost); 114 cost=exp(-cost); 115 printf("%.2f\n",1-cost); 116 } 117 return 0; 118 }