HDU 5988 ACM-ICPC Regional QingDao(最小费用最大流)

来源:互联网 发布:664uu com新域名 编辑:程序博客网 时间:2024/06/08 09:51

Coding Contest

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

Problem Description

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 theui-th block to the vi-th block. Your task is to solve the lunch issue. According to the arrangement, there aresi 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 ofpi to touch
the wires and affect the whole networks. Moreover, to protect these wires, no more thanci 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.

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 andbi (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.

Output

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

Sample Input

14 42 00 33 00 31 2 5 0.53 2 5 0.51 4 5 0.53 4 5 0.5

Sample Output

0.50

Source

2016ACM/ICPC亚洲区青岛站-重现赛(感谢中国石油大学)



        去年青岛站regional原题,在两个人的情况下做了四道题,按照现场排名大概六十多……

        我记得小肥羊学长和我说过,regional很喜欢考网络流的题目。然后做了原题,果不其然。这道题就是一个网络流的题目,而且个人感觉比较裸。题目大致意思就是,在acm比赛中,选手要在比赛中吃饭,然后在某些供应点有一定数量的人还有一定数量的饭。当然了,可能出现供不应求的情况,此时的话选手就得走到别的供应点去拿饭吃。因此还给出了一些路径,对应路径还有容量,但是这路上会有其他选手的电脑,所以走的时候每一条路都会有一个碰到电线的概率。但是第一个走过该条路的人不会碰到电线,现在你的任务就是使得所有人都可以吃到饭,而且碰到电线概率最小的方案的概率是多少。

        这题要注意的点就是概率的计算,他给出的概率是碰到电线的概率,为了方便计算,我们都统一转换为计算不碰到电线的概率,最后再用1减去它即可。原因就是,如果是计算不碰到电线的概率,那么就只需要相乘就行了,但如果是直接求,则要先减后乘,不太好实现。然后权值变成了相乘,为了套上网络流模型,所以我们对它取对数。但很快又发现取了对数之后变成了负数(概率小于一)。本来我们求碰到电线的概率最小,对应求不碰到电线概率最大,本来要求最大费用最大流,但是我们可以对那个取对数之后的概率再取相反数,这样求最小费用最大流即可。套上模板一切搞定。最后只需要对求出来的费用先取相反数再取exp,最后再用1减去即可。在提示一点,在spfa増广的时候,及得用上eps。具体见代码:

#include<bits/stdc++.h>const int maxn = 205;#define inf 1e9#define eps 1e-8using namespace std;struct Edge{    int from,to,cap,flow;double cost;Edge(){}Edge(int f,int t,int c,int fl,double co):from(f),to(t),cap(c),flow(fl),cost(co){}};int n,m,s,t;struct MCMF{    int n,m,s,t;vector<Edge>edges;vector<int>g[maxn];bool inq[maxn];double d[maxn];int p[maxn];int a[maxn];void init(int n,int s,int t){    this->n=n;this->s=s;this->t=t;edges.clear();for(int i = 0;i<=n;i++)g[i].clear();}void AddEdge(int from,int to,int cap,double cost){    edges.push_back(Edge(from,to,cap,0,cost));edges.push_back(Edge(to,from,0,0,-cost));m=edges.size();g[from].push_back(m-2);g[to].push_back(m-1);}bool BellmanFord(int &flow,double &cost){    for(int i = 0;i<=n;i++)d[i]=inf;memset(inq,0,sizeof(inq));d[s]=0,a[s]=inf,inq[s]=1,p[s]=0;queue<int>q;q.push(s);while(!q.empty()){    int u = q.front();q.pop();inq[u]=0;for(int i = 0;i<g[u].size();i++){    Edge &e = edges[g[u][i]];if(e.cap>e.flow&&d[e.to]>d[u]+e.cost+eps){    d[e.to]=d[u]+e.cost;p[e.to]=g[u][i];a[e.to]=min(a[u],e.cap-e.flow);if(!inq[e.to]){    q.push(e.to);inq[e.to]=1;}}}}if(d[t]==inf)return false;flow+=a[t];cost+=a[t]*d[t];int u = t;while(u!=s){            edges[p[u]].flow+=a[t];edges[p[u]^1].flow-=a[t];u=edges[p[u]].from;}return true;}    double Min_cost(int &flow,double &cost){    flow=0,cost=0;while(BellmanFord(flow,cost));return cost;}}mc;int main(){int T_T;cin>>T_T;while(T_T--){scanf("%d%d",&n,&m);s=0; t=n+1; mc.init(n*2+1,s,t); for(int i=1;i<=n;i++){int a,b;scanf("%d%d",&a,&b);if (a>b) mc.AddEdge(s,i,a-b,0);if (a<b) mc.AddEdge(i,t,b-a,0);}for(int i=1;i<=m;i++){int u,v,cap; double cost;scanf("%d%d%d%lf",&u,&v,&cap,&cost);cost=1-cost;if (cap>1){mc.AddEdge(u,v,1,0);mc.AddEdge(u,v,cap-1,-log(cost));}if (cap==1) mc.AddEdge(u,v,1,0);}double cost;int flow;cost=mc.Min_cost(flow,cost);printf("%.2f\n",1-exp(-cost));}return 0;}

阅读全文
0 0
原创粉丝点击