题意:有一个管子要运输液体物质,物体的流速不能超过管子的容量,且物质不能再节点有积累,即每个节点的流入量等于流出量,在第一个节点生产的物质的流速与第n个节点的流速一样,求第一个节点的生产速度最小是多少,要是没有满足的情况输出:Impossible;
给出节点的个数n个管子的个数m,然后m行给出四个数Ui,Vi,Zi,Ci,当Ci=1的时候,要求该段管子的流量为管子容量值,否则是(0,Zi),管子的流向是单向的,1-n没有直接的管子相连;
若存在最小流量,就输出最小流量,以及每根管子的流量
分析:
(1)增加超级源点st和超级汇点sd,对于有上下界的边(i,j)流量(L,R)变为R-L,然后i与sd连接容量是L,st与j连接容量是L;网络中规定不能有流量流入st,也不能有流量流入sd;
(2)做一次最大流Dinic;
(3)在汇点sd到st连一条容量是inf的边;
(4)在做一次最大流Dinic
(5)当且仅当附加弧都满流是有可行流,最后的最小流是flow[sd->st]^1],st到sd的最大流就是sd到st的最小流;
程序:
#include"stdio.h" #include"string.h" #include"queue" #include"stack" #define M 222 #define inf 100000000 using namespace std; struct node { int u,v,w,c,next; }edge[M*M*2]; int t,head[M],work[M],dis[M]; void init() { t=0; memset(head,-1,sizeof(head)); } void add(int u,int v,int w,int c) { edge[t].u=u; edge[t].v=v; edge[t].w=w; edge[t].c=c; edge[t].next=head[u]; head[u]=t++; edge[t].u=v; edge[t].v=u; edge[t].w=0; edge[t].c=c; edge[t].next=head[v]; head[v]=t++; } int bfs(int source,int sink) { memset(dis,-1,sizeof(dis)); queue<int>q; q.push(source); dis[source]=0; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(edge[i].w&&dis[v]==-1) { dis[v]=dis[u]+1; q.push(v); if(v==sink) return 1; } } } return 0; } int dfs(int cur,int a,int sink) { if(cur==sink)return a; for(int &i=work[cur];i!=-1;i=edge[i].next) { int v=edge[i].v; if(edge[i].w&&dis[v]==dis[cur]+1) { int tt=dfs(v,min(a,edge[i].w),sink); if(tt) { edge[i].w-=tt; edge[i^1].w+=tt; return tt; } } } return 0; } int Dinic(int start,int sink) { int ans=0; while(bfs(start,sink)) { memcpy(work,head,sizeof(head)); while(int tt=dfs(start,inf,sink)) ans+=tt; } return ans; } int main() { int n,m,i; while(scanf("%d%d",&n,&m)!=-1) { init(); int source=0; int sink=n+1; int sum=0; queue<int>q;//记录输入的边的编号 while(m--) { int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d); if(d==1) { add(a,b,c-c,c); q.push(t-2); add(a,sink,c,0); add(source,b,c,0); sum+=c; } else { add(a,b,c,c); q.push(t-2); } } int ans=Dinic(source,sink);//第一次求最大流 add(n,1,inf,0); int ans1=Dinic(source,sink);//第二次求最大流 if(ans+ans1!=sum)//判断是否是满流 { printf("Impossible\n"); continue; } printf("%d\n",edge[(t-1)].w);//最小流的值 int kk=0; while(!q.empty()) { if(kk==0) printf("%d",edge[(q.front())].c-edge[(q.front())].w); else printf(" %d",edge[(q.front())].c-edge[(q.front())].w); q.pop(); kk++; } printf("\n"); } }