1. 程式人生 > >POJ 3204 Road Reconstruction-網路流-最小割邊集

POJ 3204 Road Reconstruction-網路流-最小割邊集

題意

一個由n個點,m條邊構 成的有向圖,每條邊都有一定的流量。現在求存在多少條邊,在增加這些邊的流量後從1點到n的總流量會增加。

分析

先求最大流。在得到最大流f後的殘量網路G_f中,從s開始DFS,所有能遍歷到的點構成點集S。沒有搜尋到的構成點集T,兩集合間的邊構成最小割邊集。
注意:雖然 最小割[S,T]的邊都是滿流邊,但是滿流邊不一定是最小割邊集。如下面的二分圖的例子
在這裡插入圖片描述
圖(a)給出了一個基於二分圖構造的流網路。由於從X部到Y部都是容量均為正無限的邊,都不可能是最小割中的邊,有人便會錯誤地認為與源或匯關聯的滿流邊便組成了最小割(圖(a)的紅色邊)。然而實際上,在該網路的殘留網路中,結點2與3應該與源s是連通的(圖(b)的藍色路徑),所以最小割應該是圖(b)中的紅色邊。

【本題做法】
做一次最大流
S出發dfs正向邊,標記搜尋到的點集S’
T出發dfs反向邊,標記搜尋到的點集T’
列舉所有的邊,如果一條邊的端點屬於不同的點集,且該邊為滿流,則是割邊

參考程式碼

#include<iostream>
#include<vector>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
#define in rad()
inline int rad(){
	int
x=0,f=1;char c=getchar();while(c>'9'||c<'0')c=getchar(); if(c=='-')f=-1,c=getchar();while(c>='0'&&c<='9')x=x*10+c-48,c=getchar(); return x*f; } const int maxn=1e5+10; const int maxm=4e6+100; const int inf=1e9; struct Edge { int u,v,w,nxt; } e[maxm]; int first[maxn]= {},cnt=1,S,T; inline
void add(int u,int v,int w) { e[++cnt].v=v;e[cnt].u=u;e[cnt].w=w;e[cnt].nxt=first[u];first[u]=cnt; } inline void ins(int u,int v,int w){ add(u,v,w);add(v,u,0); } int n,m; namespace D{ int dis[maxn],cur[maxn]; int bfs(int s,int t){ memset(dis,-1,sizeof(dis)); queue<int>q; dis[s]=0;q.push(s); while(!q.empty()){ int u=q.front();q.pop(); for(int i=first[u];i;i=e[i].nxt){ int v=e[i].v; if(dis[v]!=-1||e[i].w==0)continue; dis[v]=dis[u]+1; q.push(v); if(v==t)return 1; } } return 0; } int dfs(int u,int t,int f){ if(!f||u==t)return f; int w,used=0; for(int &i=cur[u];i;i=e[i].nxt){ int v=e[i].v; if(dis[v]!=dis[u]+1||e[i].w==0)continue; w=dfs(v,t,min(f,e[i].w)); used+=w;f-=w; e[i].w-=w;e[i^1].w+=w; if(f==0)break; } return used; } int dinic(int s,int t){ int ret=0; while(bfs(s,t)){ memcpy(cur,first,sizeof(first)); ret+=dfs(s,t,inf); } return ret; } } int f1[maxn],f2[maxn],vis[maxn]; void dfs(int u,int f[],int d){ f[u]=1 ; for(int i=first[u];i;i=e[i].nxt){ int v=e[i].v; if(e[i^d].w&&!f[v])dfs(v,f,d); } } int main(){ n=in;m=in; for(int i=1;i<=m;i++){ int u=in,v=in,w=in; ins(u,v,w); } D::dinic(0,n-1); dfs(0,f1,0); memset(vis,0,sizeof(vis)); dfs(n-1,f2,1); int ans=0; for(int i=2;i<=cnt;i+=2) if(f1[e[i].u]&&f2[e[i].v] && e[i].w==0)ans++; cout<<ans; return 0; }