1. 程式人生 > >HDU 5988 Coding Contest(費用流+浮點數)

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 }