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
相关文章
相关标签/搜索