1. 程式人生 > >JZOJ5916. 【NOIP2018模擬10.20】flow

JZOJ5916. 【NOIP2018模擬10.20】flow

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;
}