可以直接无视那长长的段落。。
+ 表示是源点, - 表示是汇点
1,2,3,,,...n 表示n个节点
要求是否存在满足 下界限制的最小的流
如果不存在输出 impossible
最下界最小流。。 看 周源 《一种简易的方法求解流量有上下界的网络中网络流问题》 里面介绍的时候是讲用二分思想。。但是 = =有更简单的
先求是否存在可行流。。
则判断 无源无汇情况下是否存在可行流, 则用无源无汇的建图方式
....
src0,dest0 为 图中给出的 源点与汇点, s,t为新增的附加源点与汇点
1. 构造附加网络(不添加[t,s]边)
2. 对s、t求最大流
---- 上面为无源无汇建图方式 , src0,dest0 是 + 与 - 那两个题目中所给的源点跟汇点,所以要放到无源无汇中跑
求出此时的 最大流 sum1
之后
3. 添加[ dest0 ,src0 ] 无穷大 这条边
4. 对s、t 再次求最大流
此时得到最大流 sum2
5. 若s、t 的 sum1 + sum2 == 无源无汇时的满流,则[t,s]的流量就是最小流
从残留网络中输出答案即可
//tpl
//ipqhjjybj_tpl.h
//header.h
/*
src0,dest0 为 图中给出的 源点与汇点, s,t为新增的附加源点与汇点
1. 构造附加网络(不添加[t,s]边)
2. 对s、t求最大流
---- 上面为无源无汇建图方式 , src0,dest0 是 + 与 - 那两个题目中所给的源点跟汇点,所以要放到无源无汇中跑
求出此时的 最大流 sum1
之后
3. 添加[ dest0 ,src0 ] 无穷大 这条边
4. 对s、t 再次求最大流
此时得到最大流 sum2
5. 若s、t 的 sum1 + sum2 == 无源无汇时的满流,则[t,s]的流量就是最小流
从残留网络中输出答案即可
*/
#include <cstdio>
#include <cstdlib>
#include <map>
#include <set>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <sstream>
#include <math.h>
#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pLL pair<long long ,long long>
#define pb(x) push_back(x)
#define rep(i,j,k) for(int i = j; i < k;i++)
#define MAX(x,a) x=((x)<(a))?(a):(x);
#define MIN(x,a) x=((x)>(a))?(a):(x);
using namespace std;
const int N = 500;
int n,m,tot;
int s,t;
int sum;
struct node{
int u,v,w,next;
node(){}
node(int _u,int _v,int _w,int _next){
u=_u,v=_v,w=_w,next=_next;
}
}edge[N*N];
int head[N],cur[N],dis[N];
int pre[N],gap[N],aug[N];
const int oo=0x3f3f3f3f;
void addEdge(int u,int v,int w){
edge[tot]=node(u,v,w,head[u]);
head[u]=tot++;
edge[tot]=node(v,u,0,head[v]);
head[v]=tot++;
}
int SAP(int s,int e,int n){
int max_flow=0,v,u=s;
int id,mindis;
aug[s]=oo;
pre[s]=-1;
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
gap[0]=n;
for(int i=0;i <= n;i++)
cur[i]=head[i];
while(dis[s]<n){
if(u==e){
max_flow += aug[e];
for(v=pre[e]; v!=-1; v=pre[v]){
int ed=cur[v];
edge[ed].w -= aug[e];
edge[ed^1].w += aug[e];
aug[v]-=aug[e];
if(edge[ed].w==0) u=v;
}
}
bool flag=false;
for(id=cur[u]; id!=-1;id=edge[id].next){
v=edge[id].v;
if(edge[id].w > 0 && dis[u]==dis[v]+1){
flag=true;
pre[v]=u;
cur[u]=id;
aug[v]=min(aug[u],edge[id].w);
u=v;
break;
}
}
if(flag==false){
if(--gap[dis[u]] == 0) break;
int mindis=n;
for(id=head[u]; id!=-1; id=edge[id].next){
v=edge[id].v;
if(edge[id].w>0 && dis[v] < mindis){
mindis = dis[v];
cur[u]=id;
}
}
dis[u] = mindis + 1;
gap[dis[u]]++;
if(u!=s)u=pre[u];
}
}
return max_flow;
}
char s1[10],s2[10];
int in[N];
int max_flow;
int getNum(char fs[]){
if(fs[0] == '+')return s;
else if(fs[0] == '-') return t;
else return atoi(fs);
}
int solve(){
int i,src0,dest0;
src0 = s, dest0 = t;
s = n+2, t = n+3;
rep(i,0,dest0+1)
if(in[i]>0) addEdge(s,i,in[i]);
else if(in[i]<0) addEdge(i,t,-in[i]),max_flow += -in[i];
int ans1 = SAP(s,t,n+4);
addEdge(dest0,src0,oo);
int kk = SAP(s,t,n+4);
if(kk+ans1 == max_flow)
return edge[tot-1].w;
else return -1;
}
int main(){
while(scanf("%d %d",&n,&m)!=EOF){
if(n==0 && m==0) break;
memset(head,-1,sizeof(head));
memset(in,0,sizeof(in));
s = sum = tot =0; t=n+1;
max_flow = 0;
rep(i,0,m){
int l,r,w;
scanf("%s %s %d",s1,s2,&w);
l = getNum(s1),r = getNum(s2);
// printf("l=%d r=%d w=%d\n",l,r,w);
addEdge(l,r,oo);
in[r]+=w, in[l]-=w;
}int ans=0;
if((ans=solve())>=0) printf("%d\n",ans);
else puts("impossible");
}
return 0;
}