JZOJ5916. 【NOIP2018模擬10.20】flow
阿新 • • 發佈:2018-11-03
Description
你是申國的一個地方長官,你手下有n個城市。
為了加強基礎設施建設,在2020全面建成小康社會,統籌推進經濟建設、政治建設、文化建設、社會建設、生態文明建設,堅定實施科教興國戰略、人才強國戰略、創新驅動發展戰略、鄉村振興戰略、區域協調發展戰略、可持續發展戰略、軍民融合發展戰略,突出抓重點、補短板、強弱項,特別是要堅決打好防範化解重大風險、精準脫貧、汙染防治的攻堅戰,使全面建成小康社會得到人民認可、經得起歷史檢驗。你認為本省的水利調配非常有問題,這導致部分地區出現嚴重的缺水,而部分地區卻全年洪災氾濫。
於是你打算將原有的但是已經廢棄了的m條水管重新使用。第i條水管連線城市xi和yi。這些水管聯通了所有城市。每座城市對水的需求不同設為ai,部分城市處於缺水狀態,ai為正,缺水量剛好為ai mol。部分城市因為有水庫,ai為負,它需要向外輸送-ai mol的水才能不形成洪災。對於每條水管,你需要決定它的輸送量fi,若fi為正則表示從xi向yi輸送fi mol的水,fi為負則表示從yi向xi輸送-fi mol的水。
你需要做到每個城市都剛好滿足它的需求,即缺ai mol水的城市需要剛好輸入ai的水,而多出-ai mol水的城市需要剛好輸出-ai mol水。
你需要判斷能否滿足要求,若滿足,你還需要輸出所有的f。
題解
判斷是否合法很簡單,
就是看看a的和是否為0。
現在考慮如何構造出一種合法解。
一種很簡單的方法就是先構造一棵生成樹,
強制只用樹上面的邊,這樣就可以輕鬆求出一組合法解。
code
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <string.h> #include <cmath> #include <math.h> #define ll long long #define N 300003 #define M 103 #define db double #define P putchar #define G getchar using namespace std; char ch; void read(int &n) { n=0; ch=G(); while((ch<'0' || ch>'9') && ch!='-')ch=G(); int w=1; if(ch=='-')w=-1,ch=G(); while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G(); n*=w; } void write(ll x){if(x>9) write(x/10);P(x%10+'0');} int n,m,x,y,f[N],nxt[N*2],to[N*2],id[N*2],lst[N],tot,a[N]; ll s,v[N],ans[N]; int get(int x){return f[x]=(f[x]==x?x:get(f[x]));} void ins(int x,int y,int z) { nxt[++tot]=lst[x]; to[tot]=y; id[tot]=z; lst[x]=tot; } void dfs(int x,int fa) { v[x]=a[x]; for(int i=lst[x];i;i=nxt[i]) if(to[i]^fa) { dfs(to[i],x); v[x]=v[x]+v[to[i]]; if(i&1)ans[id[i]]=v[to[i]];else ans[id[i]]=-v[to[i]]; } } int main() { freopen("flow.in","r",stdin); freopen("flow.out","w",stdout); read(n); for(int i=1;i<=n;i++) read(a[i]),f[i]=i,s=s+a[i]; if(s) { puts("Impossible"); return 0; } puts("Possible"); read(m);tot=0; for(int i=1;i<=m;i++) { read(x);read(y); if(get(x)^get(y)) { ins(x,y,i); ins(y,x,i); f[get(x)]=get(y); } } dfs(1,0); for(int i=1;i<=m;i++) { if(ans[i]<0)P('-'),ans[i]=-ans[i]; write(ans[i]);P('\n'); } return 0; }