HDU–5988-Coding Contest(最小費用最大流變形)

Coding Contest

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2653    Accepted Submission(s): 579

Problem Descriptionc++

A coding contest will be held in this university, in a huge playground. The whole playground would be divided into N blocks, and there would be M directed paths linking these blocks. The i-th path goes from the ui-th block to the vi-th block. Your task is to solve the lunch issue. According to the arrangement, there are si competitors in the i-th block. Limited to the size of table, bi bags of lunch including breads, sausages and milk would be put in the i-th block. As a result, some competitors need to move to another block to access lunch. However, the playground is temporary, as a result there would be so many wires on the path.
For the i-th path, the wires have been stabilized at first and the first competitor who walker through it would not break the wires. Since then, however, when a person go through the i - th path, there is a chance of pi to touch
the wires and affect the whole networks. Moreover, to protect these wires, no more than ci competitors are allowed to walk through the i-th path.
Now you need to find a way for all competitors to get their lunch, and minimize the possibility of network crashing.git

Input算法

The first line of input contains an integer t which is the number of test cases. Then t test cases follow.
For each test case, the first line consists of two integers N (N ≤ 100) and M (M ≤ 5000). Each of the next N lines contains two integers si and bi (si , bi ≤ 200).
Each of the next M lines contains three integers ui , vi and ci(ci ≤ 100) and a float-point number pi(0 < pi < 1).
It is guaranteed that there is at least one way to let every competitor has lunch.ide

Outputui

For each turn of each case, output the minimum possibility that the networks would break down. Round it to 2 digits.this

Sample Inputspa

1 4 4 2 0 0 3 3 0 0 3 1 2 5 0.5 3 2 5 0.5 1 4 5 0.5 3 4 5 0.5code

Sample Outputblog

0.50three


思路:

這是一個最小費用最大流的變形題目。

要仔細讀懂題目,題目要求的是崩潰的最小可能性。因爲崩潰多是由一條邊或多條邊一塊兒的,因此正着求崩潰機率很難求,咱們反着思考,用1去減每條邊都不引發圖崩潰的機率即爲崩潰的機率。

因爲求的是最小,並且邊有容量限制,咱們很天然的想到了最小費用最大流(對於不崩潰的機率應該是最大費用最大流)

建圖時,某個點有人則想s連一條容量爲人數的邊,有食物則向t連一條容量爲是無數的邊,其餘的邊按照題目的數據相連便可,這個很好處理。

還有一個條件是某條路第一遍走的時候是沒有花費的。個人處理方法是將一條容量爲c,花費爲w的邊拆成兩條邊:容量爲c-1,花費爲w的一條邊;容量爲1,花費爲1.0的一條邊(花費爲1.0是爲了確保不會對最終結果產生影響)。

細節不少,因爲機率要想乘因此初始化時要注意,算一條增廣路徑對總結果的貢獻時也要注意是乘方而不是簡單的相乘。

代碼1:求增廣路徑時直接求最長路

  1 /*
 2 * @FileName: D:\代碼與算法\2017訓練比賽\2016青島區域賽\g.cpp
 3 * @Author: Pic
 4 * @Created Time: 2017/10/7 12:46:48
 5 */
  6 #include <bits/stdc++.h>
  7 using namespace std;
  8 const double INF = -1*10.0;
  9 const int maxn=200+10;
 10 
 11 struct Edge
 12 {
 13     int from,to,cap,flow;
 14 	double cost;
 15     Edge(){}
 16     Edge(int f,int t,int c,int fl,double co):from(f),to(t),cap(c),flow(fl),cost(co){}
 17 };
 18 
 19 struct MCMF
 20 {
 21     int n,m,s,t;
 22     vector<Edge> edges;
 23     vector<int> G[maxn];
 24     bool inq[maxn];     //是否在隊列
 25     double d[maxn];        //Bellman_ford單源最短路徑
 26     int p[maxn];        //p[i]表從s到i的最小費用路徑上的最後一條弧編號
 27     int a[maxn];        //a[i]表示從s到i的最小殘量
 28 
 29     //初始化
 30     void init(int n,int s,int t)
 31     {
 32         this->n=n, this->s=s, this->t=t;
 33         edges.clear();
 34         for(int i=0;i<n;++i) G[i].clear();
 35     }
 36 
 37     //添加一條有向邊
 38     void AddEdge(int from,int to,int cap,double cost)
 39     {
 40         edges.push_back(Edge(from,to,cap,0,cost));
 41         edges.push_back(Edge(to,from,0,0,-cost));
 42         m=edges.size();
 43         G[from].push_back(m-2);
 44         G[to].push_back(m-1);
 45     }
 46 
 47     //求一次增廣路
 48     bool BellmanFord(int &flow, double &cost)
 49     {
 50         for(int i=0;i<n;++i) d[i]=INF;
 51         memset(inq,0,sizeof(inq));
 52         d[s]=1.0, a[s]=1e9+30, inq[s]=true, p[s]=0;
 53         queue<int> Q;
 54         Q.push(s);
 55         while(!Q.empty())
 56         {
 57 			//cout<<"Q"<<endl;
 58             int u=Q.front(); Q.pop();
 59             inq[u]=false;
 60             for(int i=0;i<G[u].size();++i)
 61             {
 62                 Edge &e=edges[G[u][i]];
 63 				double tmp=(d[u]*e.cost);
 64 				//tmp=-1*fabs(tmp);
 65                 if( e.cap>e.flow && d[e.to] < tmp )
 66                 {
 67                     d[e.to]=tmp;
 68                     p[e.to]=G[u][i];
 69                     a[e.to]= min(a[u],e.cap-e.flow);
 70                     if(!inq[e.to]){ Q.push(e.to); inq[e.to]=true; }
 71                 }
 72             }
 73         }
 74 		//cout<<d[t]<<endl;
 75         //if(fabs(d[t]-INF)<1e-3) return false;
 76         if(d[t]<0) return false;
 77         flow += a[t];
 78 		for(int i=0;i<a[t];i++) cost*=(d[t]);
 79         int u=t;
 80         while(u!=s)
 81         {
 82             edges[p[u]].flow += a[t];
 83             edges[p[u]^1].flow -=a[t];
 84             u = edges[p[u]].from;
 85         }
 86         return true;
 87     }
 88 
 89     //求出最小費用最大流
 90     double Min_cost()
 91     {
 92         int flow=0;double cost=1.0;
 93 		while(BellmanFord(flow,cost)) ;
 94         return cost;
 95     }
 96 }MM;
 97 int main()
 98 {
 99 //	freopen("data.in","r",stdin);
100 	//freopen("data.out","w",stdout);
101 	int t;
102    	scanf("%d",&t);
103 	while(t--){
104 		int n,m;
105 		scanf("%d%d",&n,&m);
106 		MM.init(n+2,0,n+1);
107 		int x,y;
108 		for(int i=1;i<=n;i++){
109 			scanf("%d%d",&x,&y);
110 			if(x!=0)
111 				MM.AddEdge(0,i,x,1.0);
112 			if(y!=0)
113 				MM.AddEdge(i,n+1,y,1.0);
114 		}
115 		int u,v,c;double w;
116 		for(int i=1;i<=m;i++){
117 			scanf("%d%d%d%lf",&u,&v,&c,&w);
118 			//MM.AddEdge(u,v,c,w);
119 			if(c>0){
120 				MM.AddEdge(u,v,c-1,1.0-w);
121 				MM.AddEdge(u,v,1,1.0);
122 			}
123 		}
124 		double res=fabs(MM.Min_cost());
125 		//cout<<res<<endl;
126 		res=1.0-res;
127 		if(res>=1.0) res=1.0;
128 		printf("%.2lf\n",res);
129 	}
130 	return 0;
131 }
View Code

代碼2:花費取負,求最小費用最大流,注意初始化的值

  1 /*
 2 * @FileName: D:\代碼與算法\2017訓練比賽\2016青島區域賽\g.cpp
 3 * @Author: Pic
 4 * @Created Time: 2017/10/7 12:46:48
 5 */
  6 #include <bits/stdc++.h>
  7 using namespace std;
  8 const double INF = 1e8;
  9 const int maxn=200+10;
 10 
 11 struct Edge
 12 {
 13     int from,to,cap,flow;
 14 	double cost;
 15     Edge(){}
 16     Edge(int f,int t,int c,int fl,double co):from(f),to(t),cap(c),flow(fl),cost(co){}
 17 };
 18 
 19 struct MCMF
 20 {
 21     int n,m,s,t;
 22     vector<Edge> edges;
 23     vector<int> G[maxn];
 24     bool inq[maxn];     //是否在隊列
 25     double d[maxn];        //Bellman_ford單源最短路徑
 26     int p[maxn];        //p[i]表從s到i的最小費用路徑上的最後一條弧編號
 27     int a[maxn];        //a[i]表示從s到i的最小殘量
 28 
 29     //初始化
 30     void init(int n,int s,int t)
 31     {
 32         this->n=n, this->s=s, this->t=t;
 33         edges.clear();
 34         for(int i=0;i<n;++i) G[i].clear();
 35     }
 36 
 37     //添加一條有向邊
 38     void AddEdge(int from,int to,int cap,double cost)
 39     {
 40         edges.push_back(Edge(from,to,cap,0,cost));
 41         edges.push_back(Edge(to,from,0,0,-cost));
 42         m=edges.size();
 43         G[from].push_back(m-2);
 44         G[to].push_back(m-1);
 45     }
 46 
 47     //求一次增廣路
 48     bool BellmanFord(int &flow, double &cost)
 49     {
 50         for(int i=0;i<n;++i) d[i]=INF;
 51         memset(inq,0,sizeof(inq));
 52         d[s]=1.0, a[s]=INF, inq[s]=true, p[s]=0;
 53         queue<int> Q;
 54         Q.push(s);
 55         while(!Q.empty())
 56         {
 57 		//	cout<<"Q"<<endl;
 58             int u=Q.front(); Q.pop();
 59             inq[u]=false;
 60             for(int i=0;i<G[u].size();++i)
 61             {
 62                 Edge &e=edges[G[u][i]];
 63 				double tmp=(d[u]*e.cost);
 64 				tmp=-1*fabs(tmp);
 65                 if( e.cap>e.flow && d[e.to] > tmp )
 66                 {
 67                     d[e.to]=tmp;
 68                     p[e.to]=G[u][i];
 69                     a[e.to]= min(a[u],e.cap-e.flow);
 70                     if(!inq[e.to]){ Q.push(e.to); inq[e.to]=true; }
 71                 }
 72             }
 73         }
 74         if(fabs(d[t]-INF)<1e3) return false;
 75         flow += a[t];
 76 		for(int i=0;i<a[t];i++) cost*=(d[t]);
 77         int u=t;
 78         while(u!=s)
 79         {
 80             edges[p[u]].flow += a[t];
 81             edges[p[u]^1].flow -=a[t];
 82             u = edges[p[u]].from;
 83         }
 84         return true;
 85     }
 86 
 87     //求出最小費用最大流
 88     double Min_cost()
 89     {
 90         int flow=0;double cost=1.0;
 91 		while(BellmanFord(flow,cost));
 92         return cost;
 93     }
 94 }MM;
 95 int main()
 96 {
 97 //	freopen("data.in","r",stdin);
 98 	//freopen("data.out","w",stdout);
 99 	int t;
100    	scanf("%d",&t);
101 	while(t--){
102 		int n,m;
103 		scanf("%d%d",&n,&m);
104 		MM.init(n+2,0,n+1);
105 		int x,y;
106 		for(int i=1;i<=n;i++){
107 			scanf("%d%d",&x,&y);
108 			if(x!=0)
109 				MM.AddEdge(0,i,x,1.0);
110 			if(y!=0)
111 				MM.AddEdge(i,n+1,y,1.0);
112 		}
113 		int u,v,c;double w;
114 		for(int i=1;i<=m;i++){
115 			scanf("%d%d%d%lf",&u,&v,&c,&w);
116 			//MM.AddEdge(u,v,c,w);
117 			if(c>0){
118 				MM.AddEdge(u,v,c-1,w-1.0);
119 				MM.AddEdge(u,v,1,1.0);
120 			}
121 		}
122 		double res=fabs(MM.Min_cost());
123 		//cout<<res<<endl;
124 		res=1.0-res;
125 		if(res>=1.0) res=1.0;
126 		printf("%.2lf\n",res);
127 	}
128 	return 0;
129 }
View Code
相關文章
相關標籤/搜索