【アクティブスポット上下境界最小流】[SGU 176]Flow construction
テーマ分析:無源汇点上下界最大流のように図を作り、SS->STから1回走り、t->sは容量+∞の辺を1本つなぎ、1回走り、t->sという辺の流量は最小流である.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define INF 0x7f7f7f7f
#define MAXN 100
using namespace std;
int n,m,d[MAXN+10],S,T,num,dist[MAXN+10],vd[MAXN+10],tot,l[MAXN*MAXN+10],flow;
void Read(int &x){
char c;
while(c=getchar(),c!=EOF)
if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
return;
}
}
struct node{
int v,cap;
node *next,*back;
}*adj[MAXN+10],edge[MAXN*MAXN+10],*ecnt=edge,*epos[MAXN*MAXN+10];
void addedge(int u,int v,int cap,int pos){
node *p=++ecnt;
p->v=v;
p->cap=cap;
p->next=adj[u];
epos[pos]=p;
adj[u]=p;
p=p->back=++ecnt;
p->v=u;
p->cap=0;
p->next=adj[v];
adj[v]=p;
p->back=ecnt-1;
}
void read(){
Read(n),Read(m);
int i,u,v,z,c;
for(i=1;i<=m;i++){
Read(u),Read(v),Read(z),Read(c);
if(c==1)
d[u]-=z,d[v]+=z,epos[i]=0,l[i]=z;
else
addedge(u,v,z,i);
}
S=n+1,T=n+2;
for(i=1;i<=n;i++)
if(d[i]>0)
addedge(S,i,d[i],0),tot+=d[i];
else if(d[i]<0)
addedge(i,T,-d[i],0);
}
int dfs(int u,int augu){
if(u==T)
return augu;
int v,augv=0,delta,mind=num-1;
for(node *p=adj[u];p;p=p->next)
if(p->cap){
v=p->v;
if(dist[u]==dist[v]+1){
delta=min(augu-augv,p->cap);
delta=dfs(v,delta);
augv+=delta;
p->cap-=delta;
p->back->cap+=delta;
if(augu==augv||dist[S]>=num)
return augv;
}
mind=min(mind,dist[v]);
}
if(!augv){
if(!--vd[dist[u]])
dist[S]=num;
dist[u]=mind+1;
vd[dist[u]]++;
}
return augv;
}
void mcmf(){
memset(dist,0,sizeof dist);
memset(vd,0,sizeof vd);
num=n+2;
vd[0]=num;
while(dist[S]<num)
flow+=dfs(S,INF);
}
void print(){
if(flow!=tot){
puts("Impossible");
return;
}
printf("%d
",epos[m+1]->back->cap);
for(int i=1;i<m;i++)
if(epos[i])
printf("%d ",epos[i]->back->cap);
else
printf("%d ",l[i]);
if(epos[m])
printf("%d
",epos[m]->back->cap);
else
printf("%d
",l[m]);
}
int main()
{
read();
mcmf();
addedge(n,1,INF,m+1);
mcmf();
print();
}