1. 程式人生 > >ZOJ2314 Reactor Cooling

ZOJ2314 Reactor Cooling

wap pac 流量 網絡流 tin clas scanf set 這樣的

題目大意是這樣的,給出n個點和m條邊,每個邊有一個流量的上下界,問是否存在一個循環的流量。這就是典型的無匯源點的上下界網絡流,也就是循環流。做法是這樣的,首先每條邊我們都添加最少的流量,由於要滿足流量守恒的條件,即每個點的流出量等於流入量,那麽我們嘗試進行修改,添加新的流量。我們記錄一下每個點流出量與流入量的差,新建虛擬匯點源點,如果一個點流入量大於流出量,那麽我們把他連向匯點,反之連向源點(容量都取絕對值),然後原來的m條邊流量全部變為上下界的差。這樣有源點有匯點的網絡流就建出來了,跑一下最大流,如果最大流等於我們源點連出來的所有邊的容量之和,那麽就是有解的,反之就無解。因為我們新建的網絡流源點與匯點的流量之和一定相同(原圖上每個邊的貢獻為0,兩兩抵消),如果最大流滿流意味著我們在每條邊流量為下限的時候找到了一條新的流量使得原圖的流量守恒,而我們取得是流量的下限,如果此時找不到流量守恒的流量,那麽肯定就無解了。 —— by VANE

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N=300;
const int M=N*400;
int ss,tt,pre[M],other[M],last[N],l=1,cap[M],low[M];
int n,m,d[N],flow[M],dis[N];
void add(int a,int b,int c)
{
    ++l;pre[l]=last[a];last[a]=l;other[l]=b;cap[l]=c;flow[l]=0
; swap(a,b);++l;pre[l]=last[a];last[a]=l;other[l]=b;cap[l]=0;flow[l]=0; } bool bfs() { memset(dis,0,sizeof dis); queue<int> q; q.push(ss); dis[ss]=1; while(!q.empty()) { int u=q.front();q.pop(); for(int p=last[u];p;p=pre[p]) {
int v=other[p]; if(!cap[p]||dis[v]) continue; dis[v]=dis[u]+1; q.push(v); } } if(dis[tt]) return 1; return 0; } int dfs(int x,int f) { if(x==tt) return f; if(f==0) return 0; int res=f; for(int p=last[x];p;p=pre[p]) { int v=other[p]; if(dis[v]!=dis[x]+1||!cap[p]) continue; if(!res) break; int tmp=dfs(v,min(cap[p],res)); res-=tmp; cap[p]-=tmp; flow[p]+=tmp; cap[p^1]+=tmp; flow[p^1]-=tmp; if(tmp==0) dis[v]=-1; } return f-res; } int dinic() { int res=0; while(bfs()) res+=dfs(ss,1e9); return res; } int main() { int T; scanf("%d",&T); while(T--) { l=1; memset(d,0,sizeof d); memset(last,0,sizeof last); scanf("%d%d",&n,&m); ss=n+1;tt=n+2; for(int i=1;i<=m;++i) { int a,b,c; scanf("%d%d%d%d",&a,&b,&low[i],&c); add(a,b,c-low[i]); d[a]+=low[i]; d[b]-=low[i]; } int tot=0; for(int i=1;i<=n;++i) { if(d[i]<0) add(ss,i,-d[i]); else add(i,tt,d[i]),tot+=d[i]; } if(dinic()!=tot) puts("NO"); else { puts("YES"); for(int i=1;i<=m;++i) printf("%d\n",flow[i<<1]+low[i]); } } }

ZOJ2314 Reactor Cooling