UVa 11248 网络扩容(最大流(需要优化))

https://vjudge.net/problem/UVA-11248

题意:

给定一个有向网络,每条边均有一个容量。问是否存在一个从点1到点N,流量为C的流。如果不存在,是否可以恰好修改一条弧的容量,使得存在这样的流。

思路:

先求一遍最大流,如果大于等于C,那么就直接输出possible。

否则的话就是最大流达不到C,那么对哪些边进行扩容呢,肯定是选择最小割!

将最小割的边集全部求出来,之后每条边都尝试将容量变为C,看看能否达到要求。

优化一:求完最大流后把流量留着,以后每次在它的基础上增广。

优化二:每次没必要求出最大流,增广到流量至少为C时就可以停下来。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<queue>
  7 #include<cmath>
  8 #include<map>
  9 using namespace std;
 10
 11 const int maxn=100+5;
 12 const int INF=0x3f3f3f3f;
 13
 14 struct Edge
 15 {
 16     int from,to,cap,flow;
 17     Edge(int u,int v,int w,int f):from(u),to(v),cap(w),flow(f){}
 18 };
 19
 20 struct Dinic
 21 {
 22     int n,m,s,t;
 23     vector<Edge> edges;
 24     vector<int> G[maxn];
 25     bool vis[maxn];
 26     int cur[maxn];
 27     int d[maxn];
 28
 29     void init(int n)
 30     {
 31         this->n=n;
 32         for(int i=0;i<n;++i) G[i].clear();
 33         edges.clear();
 34     }
 35
 36     void AddEdge(int from,int to,int cap)
 37     {
 38         edges.push_back( Edge(from,to,cap,0) );
 39         edges.push_back( Edge(to,from,0,0) );
 40         m=edges.size();
 41         G[from].push_back(m-2);
 42         G[to].push_back(m-1);
 43     }
 44
 45     bool BFS()
 46     {
 47         queue<int> Q;
 48         memset(vis,0,sizeof(vis));
 49         vis[s]=true;
 50         d[s]=0;
 51         Q.push(s);
 52         while(!Q.empty())
 53         {
 54             int x=Q.front(); Q.pop();
 55             for(int i=0;i<G[x].size();++i)
 56             {
 57                 Edge& e=edges[G[x][i]];
 58                 if(!vis[e.to] && e.cap>e.flow)
 59                 {
 60                     vis[e.to]=true;
 61                     d[e.to]=d[x]+1;
 62                     Q.push(e.to);
 63                 }
 64             }
 65         }
 66         return vis[t];
 67     }
 68
 69     int DFS(int x,int a)
 70     {
 71         if(x==t || a==0) return a;
 72         int flow=0, f;
 73         for(int &i=cur[x];i<G[x].size();++i)
 74         {
 75             Edge &e=edges[G[x][i]];
 76             if(d[e.to]==d[x]+1 && (f=DFS(e.to,min(a,e.cap-e.flow) ) )>0)
 77             {
 78                 e.flow +=f;
 79                 edges[G[x][i]^1].flow -=f;
 80                 flow +=f;
 81                 a -=f;
 82                 if(a==0) break;
 83             }
 84         }
 85         return flow;
 86     }
 87
 88     int Maxflow(int s,int t,int need)
 89     {
 90         this->s=s; this->t=t;
 91         int flow=0;
 92         while(BFS())
 93         {
 94             memset(cur,0,sizeof(cur));
 95             flow +=DFS(s,INF);
 96             if(flow>=need)  return flow;
 97         }
 98         return flow;
 99     }
100
101     //最小割的边集
102     vector<int> Mincut()
103     {
104         BFS();
105         vector<int> ans;
106         for(int i=0;i<edges.size();i++)
107         {
108             Edge& e=edges[i];
109             if(vis[e.from] && !vis[e.to] && e.cap>0)  ans.push_back(i);
110         }
111         return ans;
112     }
113
114     void Reduce()
115     {
116         for(int i=0;i<edges.size();i++)
117         {
118             Edge& e=edges[i];
119             e.cap-=e.flow;
120         }
121     }
122
123     void Clearflow()
124     {
125         for(int i=0;i<edges.size();i++)
126         {
127             Edge& e=edges[i];
128             e.flow=0;
129         }
130     };
131
132 }DC;
133
134 int n,e,c;
135
136 bool cmp(Edge a,Edge b)
137 {
138     return a.from<b.from||((a.from==b.from)&&(a.to<b.to));
139 }
140
141 int main()
142 {
143     //freopen("D:\\input.txt","r",stdin);
144     int kase=0;
145     while(~scanf("%d%d%d",&n,&e,&c))
146     {
147         if(!n) break;
148         DC.init(n+1);
149         int u,v,w;
150         for(int i=0;i<e;i++)
151         {
152             scanf("%d%d%d",&u,&v,&w);
153             DC.AddEdge(u,v,w);
154         }
155         printf("Case %d: ",++kase);
156         int ans=DC.Maxflow(1,n,INF);
157         if(ans>=c)
158         {
159             printf("possible\n");
160             continue;
161         }
162         vector<int> cut=DC.Mincut();
163         DC.Reduce();
164         vector<Edge> change;
165         for(int i=0;i<cut.size();i++)
166         {
167             DC.Clearflow();
168             Edge& e=DC.edges[cut[i]];
169             int temp=e.cap;
170             e.cap=c;
171             if(DC.Maxflow(1,n,c-ans)>=c-ans)  change.push_back(e);
172             e.cap=temp;
173         }
174         if(change.empty())
175         {
176             printf("not possible\n");
177             continue;
178         }
179         sort(change.begin(),change.end(),cmp);
180         printf("possible option:");
181         printf("(%d,%d)",change[0].from,change[0].to);
182         for(int i=1;i<change.size();i++)
183             printf(",(%d,%d)",change[i].from,change[i].to);
184         printf("\n");
185     }
186 }
时间: 2024-10-12 22:32:53

UVa 11248 网络扩容(最大流(需要优化))的相关文章

bzoj 1834: [ZJOI2010]network 网络扩容 -- 最大流+费用流

1834: [ZJOI2010]network 网络扩容 Time Limit: 3 Sec  Memory Limit: 64 MB Description 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. Input 输入文件的第一行包含三个整数N,M,K,表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数u,v,C,W,表示一

【bzoj1834】[ZJOI2010]network 网络扩容 最大流+最小费用流

题目描述 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. 输入 输入文件的第一行包含三个整数N,M,K,表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边. 输出 输出文件一行包含两个整数,分别表示问题1和问题2的答案. 样例输入 5 8 2 1 2 5 8 2 5 9

[ZJOI2010][bzoj1834] 网络扩容 [费用流]

题面 传送门 思路 第一问:无脑网络流跑一波 第二问: 先考虑一个贪心的结论:扩容出来的扩容流量一定要跑满 证明显然 因此我们可以把扩容费用可以换个角度思考,变成增加一点流量,花费W的费用 这样,我们就得到了一个最小费用流的模型 只要在原图基础上,对于每个原图边,加一条费用为W,无限容量的边,而原图中的所有边费用为0,就可以模拟原题需要的情况了 最后一个问题:流量增加限制K怎么处理? 我们虽然可以用spfa的费用流,一次一次增加,直到K,但是这样也太慢chou了吧? 不怕,我们加一个n+1号点,

luogu P2604 [ZJOI2010]网络扩容 |费用流

题目描述 给定一张有向图,每条边都有一个容量\(C\)和一个扩容费用\(W\).这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. 输入格式 输入文件的第一行包含三个整数\(N,M,K\),表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数\(u,v,C,W\),表示一条从u到v,容量为C,扩容费用为W的边. 输出格式 输出文件一行包含两个整数,分别表示问题1和问题2的答案. 利用残余网

[ZJOI2010]网络扩容 (最大流 + 费用流)

题目描述 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. 输入输出格式 输入格式: 输入文件的第一行包含三个整数N,M,K,表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边. 输出格式: 输出文件一行包含两个整数,分别表示问题1和问题2的答案. 输入输出样例 输入样例#

UVA 11248 Frequency Hopping (最大流+最小割)

题意:与正常的网络流一样,不过给定的第一行的最后一个数C的意思是能能否在给定的图里求出修改某一条边或者不修改某一条边是的这个图的流变成C,如果没修改就能有C,那么输出possible,通过修改能得到C输出possible+能修改的边集合,否则输出no possible 思路:(自己的是死暴力方法,直接爆了,想了很多法子都来不起,最后参照白书的思路来起了)可以先求出最大流,然后求出最小割里的弧,依次修改最小割里的弧,看能求出的最大流是否大于C PS:不优化的话很容易超时,第一个优化是把第一次求得得

uva 11248 Frequency Hopping (最大流)

uva 11248 Frequency Hopping 题目大意:给定一个有向网络,每条边均有一个容量. 问是否存在一个从点1到点N.流量为C的流.假设不存在,能否够恰好改动一条弧的容量,使得存在这种流. 解题思路:先依照题目给出的边建好图,然后跑一发最大流,得到原始最大流C1,假设C1==C或者C==0时.能够直接输出possible.假设不存在这种流.那么開始找割边,将这些割边的容量添加C,再求最大流.假设能够,那么要输出全部的方案.改动全部割边后,仍没有符合条件的流,输出 not poss

UVA 11248 - Frequency Hopping(网络流)

UVA 11248 - Frequency Hopping 题目链接 题意:给定一个网络,现在需要从1到N运输流量C,问是否可能,如果可能输出可能,如果不可能,再问是否能通过扩大一条边的容量使得可能,如果可以输出这些边(按u先排再按v排),如果不行输出不可能 思路:先做一遍网络流,然后每次在最小割上进行增加容量,需要两个优化,每次找流量找到>= c就可以了,然后每次修改容量,可以直接从之前做过的网络流继续做即可 代码: #include <cstdio> #include <cst

bzoj1834: [ZJOI2010]network 网络扩容

努力看了很久样例一直过不了...然后各种输出中间过程啊巴拉巴拉弄了1h,没办法了...然后突然想到啊原来的边可以用啊为什么不用...于是A了...感人肺腑 #include<cstdio> #include<cstring> #include<queue> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n