CodeForces - 269C Flawed Flow

http://codeforces.com/problemset/problem/269/C

题目大意:

给定一个边没有定向的无法增广的残量网络且1是源点,n是汇点,给定每条边中的流。 

让你把所有边定向的同时保证这是一个合法的无法增广的无环残量网络(n,m <=2*10^5)

题解:

这道题首先从流量守恒的角度入手

我们知道对于每个中间点来说一定满足流量守恒性质(流入量 == 流出量)

而我们又可以对所有相连的边权加和求得所有(流入它)的和(流出的它的)流量之和

所以我们可以直接把相连的边的权值之和加起来除以2,这样就可以算出来它的流入量

相应的,我们就知道了它的流出量 

但是我们知道了所有边的流入流出量有什么用呢?

如果我们知道了一个点的所有的流入量,那我们是不是就可以知道剩下的边一定是向外的呢?

答案是肯定的 

这时候我们想,要是每次我们都至少有一个点的流入都已知

那我就可以通过剩下的边都流向外面的方式去更新剩余的节点的流入量了

这种好事有没有呢?

有!并且这样的点在每次更新完后一定至少存在一个! 

所以我们直接使用类似于拓扑排序的过程来解决这道题就可以了!!!!

下面来证明这样的点一定存在:

假设在几次更新后(第一次一定存在,即源点1),不存在一个流入量已知的点,设其为u  

那么我们知道,一定存在一条流  <x,u>是我们没有成功定向的,所以说x也没有定向!

这样我们无限向前迭代,会出现两种情况  

1.我们无限迭代后,回到了源点(x = 1)。  

  这种情况下,我们知道如果x = 1那么一定知道流<x,u>已经定向方向,矛盾,不成立.

2.我们无限迭代,一直处在一个循环里。  

  这种情况不可能发生。因为流网络中不可能存在环。所以这种情况也不成立    

所以两种情况都不成立,故不存在这样的点u  

所以,至少存在一个可更新的点,证明完毕

 

Code

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 inline void read(int &x){
 7     x=0;char ch;bool flag = false;
 8     while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
 9     while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
10 }
11 inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
12 inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
13 const int maxn = 200010;
14 struct Edge{
15     int to,next,flow;
16     bool flag;
17 }G[maxn<<1];
18 int head[maxn],cnt=1;
19 inline void add(int u,int v,int c){
20     G[++cnt].to = v;
21     G[cnt].next = head[u];
22     G[cnt].flow = c;
23     head[u] = cnt;
24 }
25 int q[maxn],l,r,flow[maxn],n;
26 #define v G[i].to
27 inline void bfs(){
28     l = 0;r = -1;q[++r] = 1;
29     while(l <= r){
30         int u = q[l++];
31         for(int i = head[u];i;i=G[i].next){
32             if(G[i].flag || G[i^1].flag) continue;
33             G[i].flag = true;
34             flow[v] -= G[i].flow;
35             if(flow[v] == 0 && v != n) q[++r] = v;
36         }
37     }
38 }
39 #undef v
40 int main(){
41     int m;read(n);read(m);
42     for(int i=1,u,v,d;i<=m;++i){
43         read(u);read(v);read(d);
44         add(u,v,d);add(v,u,d);
45         flow[u] += d;flow[v] += d;
46     }
47     for(int i=1;i<=n;++i) flow[i] >>= 1;
48     bfs();
49     for(int i=2;i<=cnt;i+=2){
50         printf("%d\n",G[i^1].flag);
51     }
52     getchar();getchar();
53     return 0;
54 }

 

 

转载于:https://www.cnblogs.com/Skyminer/p/6262624.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值