学习笔记(上下界)
关于上下界网络流学习笔记
无源无汇可行流
首先对于无源无汇,也就是循环流,是没有最大流之说的。
对于每一条边有一个流量下界down,和流量上界up,那我们使得此边流量为up-down,但这样因为每条边减少的流量不一样,所以会导致流量不守恒,
解决方式:因为流入每个点的流量都被剪掉了一个下界,所以从超级源向每个点连一条流量为流入此点流量下界之和的边,而从每个点流出的流量也被减掉了一个下界,所以从每个点向超级汇连一条流量为从此点流出的流量下界之和的边。但并不是每个图都有可行流的,再跑完之后,你需要判断此流量是否可行,只要判断跑出的最大流是否等于每条边流量下界之和即可。
另外一种建边方式,其实每个点向源汇点连边中只有较大的那一条有用,令sum表示每个点流入下界总量减去流出下界总量,if(sum>0)表示流入的下界的量减去的较多,所以有源点向该点连一条流量为sum的边,反之则由该点向汇点连一条流量为-sum的边。这样建边的话判断是否满流则判断最大流是否等于所有大于0的sum的和,即判断所有与源点相连的边是否满流即可。
有源有汇可行流
对于一个有源有汇的模型,要求源点s流出总量等于汇点t的流出总量,且其他边的流量满足上下界限制,对于此类问题可以转换为无源无汇可行流,那么就要有流量流入源点,有流量流出汇点,注意到源点流出量等于汇点流入量,所以从t向s,连一条流量为inf的边,相当于把流入t的流量又流回去了,这样整个图又变成了一个无源无汇循环流模型,那么每条边的可行流流量为t—>s的反向边的流量+流量下界
有源有汇最大流
对于跑完可行流的残量网络再次从s到t跑一遍即可,那么最后的最大流等于第一次的可行流+第二次的最大流。跑之前要删掉t->s边上的流量,也要删掉超级源和超级汇连的所有边(流量设为0即可)(不然上一次跑的流量会被增广回去)
有源有汇最小流
与有源有汇最大流相反,我们需要找到满足上下界的最小流,显然我们不可能在残量网络上继续增广了,那么考虑每条边(u->v)的反向边,它代表从u->v的流量,那么我们要让这个值尽量的小,注意到,当你增广某条边时,该边的flow会减小,而反向边flow增大,所以我们增广u->v方向边,即从t向s跑一遍即可。最小流=可行流-最大流。一样要记得删边。
POJ2396
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef int sign;
typedef long long ll;
#define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
#define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
const int N=1000+5,M=5e5+5;
bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
template<typename T>T read()
{
T ans=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
return ans*f;
}
void file()
{
#ifndef ONLINE_JUDGE
freopen("2396.in","r",stdin);
freopen("2396.out","w",stdout);
#endif
}
int n,m,q;
struct edge
{
int u,v,nex,flow;
}e[M];
int head[N<<1],tt,cur[N<<1];
int up[N][N],down[N][N];
const int inf=0x3f3f3f3f;
int s,t,st,ed,tot,jud;
bool err;
void add(int x,int y,int z)
{
if(!z)return;
if(x==st)jud+=z;
++tt;e[tt].u=x;e[tt].v=y;e[tt].flow=z;e[tt].nex=head[x];head[x]=tt;
++tt;e[tt].u=y;e[tt].v=x;e[tt].flow=0;e[tt].nex=head[y];head[y]=tt;
}
void link(int x,int y,int l1,int l2)
{
if(l1>l2){err=1;return;}
add(st,y,l1);add(x,ed,l1);add(x,y,l2-l1);
}
void change(int x,int y,int z,int opt)
{
if(opt==1)cmin(up[x][y],z-1);
else if(opt==2)up[x][y]=down[x][y]=z;
else if(opt==3)cmax(down[x][y],z+1);
}
void deal(int x,int y,int z,int opt)
{
if(!x)
{
For(i,1,n)
{
if(!y)
{
For(j,1,m)
{
change(i,j,z,opt);
}
}
else
{
change(i,y,z,opt);
}
}
}
else
{
if(!y)
{
For(j,1,m)
{
change(x,j,z,opt);
}
}
else
{
change(x,y,z,opt);
}
}
}
void input()
{
char ss[10];
int x,y,z;
scanf("\n");
n=read<int>();m=read<int>();
tot=n+m;s=tot+1;t=tot+2;st=tot+3;ed=tot+4;
For(i,1,n)For(j,1,m)
{
up[i][j]=inf;
down[i][j]=0;
}
For(i,1,n)
{
x=read<int>();
link(s,i,x,x);
}
For(j,1,m)
{
y=read<int>();
link(j+n,t,y,y);
}
q=read<int>();
while(q--)
{
x=read<int>();y=read<int>();scanf("%s",ss);z=read<int>();
if(ss[0]=='<')deal(x,y,z,1);
else if(ss[0]=='=')deal(x,y,z,2);
else if(ss[0]=='>')deal(x,y,z,3);
}
}
void build()
{
For(i,1,n)For(j,1,m)link(i,j+n,down[i][j],up[i][j]);
link(t,s,0,inf);
}
int dis[N<<1],gap[N<<1];
int dfs(int u,int flow)
{
if(u==ed)return flow;
int v,f,res=flow;
for(register int &i=cur[u];i;i=e[i].nex)
{
v=e[i].v;
if(dis[u]==dis[v]+1&&e[i].flow)
{
f=dfs(v,min(res,e[i].flow));
e[i].flow-=f;e[i^1].flow+=f;
if(!(res-=f))return flow;
}
}
if(!--gap[dis[u]])dis[st]=tot+10;
++gap[++dis[u]];
return flow-res;
}
int isap()
{
int flow=0;
memset(dis,0,sizeof dis);
memset(gap,0,sizeof gap);
for(gap[0]=tot+10;dis[st]<tot+10;)
{
memcpy(cur,head,sizeof cur);
flow+=dfs(st,inf);
}
return flow;
}
int mp[N][N];
void work()
{
int u,v;
if(err||jud!=isap())printf("IMPOSSIBLE");
else
{
//For(i,2,tt)printf("%d %d %d\n",e[i].u,e[i].v,e[i].flow);
for(register int i=3;i<=tt;i+=2)
{
u=e[i].u;v=e[i].v;
if(u<=n+m&&u>n&&v<=n)
{
//printf("%d %d %d\n",u,v,e[i].flow);
mp[v][u-n]=e[i].flow;
//if(mp[v][u-n]<0)err=1;
}
}
//if(err){printf("IMPOSSIBLE");return;}
For(i,1,n)For(j,1,m)
printf("%d%c",mp[i][j]+down[i][j],(j==m&&i!=n)?'\n':' ');
}
}
void init()
{
tt=1;jud=0;err=0;
memset(head,0,sizeof head);
memset(mp,0,sizeof mp);
}
int main()
{
file();
int T=read<int>();
while(T--)
{
init();
input();
build();
work();
if(T)printf("\n\n");
}
return 0;
}
POJ1821
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef int sign;
typedef long long ll;
#define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
#define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
const int N=16000+5,K=100+5;
bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
template<typename T>T read()
{
T ans=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
return ans*f;
}
void file()
{
#ifndef ONLINE_JUDGE
freopen("1821.in","r",stdin);
freopen("1821.out","w",stdout);
#endif
}
int n,k;
int dp[K][N];
struct people
{
int l,p,s;
bool operator < (const people &x)const
{return s<x.s;}
}a[K];
void input()
{
For(i,1,k)
{
a[i].l=read<int>();
a[i].p=read<int>();
a[i].s=read<int>();
}
}
struct node
{
int sum,pos;
};
node l[N];
int head,tail;
int ans;
void work()
{
int temp;
sort(a+1,a+k+1);
//For(i,1,k)printf("%d %d %d\n",a[i].l,a[i].p,a[i].s);
For(i,1,k)
{
head=1;tail=0;
l[++tail].sum=0;l[tail].pos=0;
For(j,1,n)
{
cmax(dp[i][j],max(dp[i][j-1],dp[i-1][j]));
if(j>=a[i].s&&j<a[i].s+a[i].l)
{
while(head<=tail&&l[head].pos+a[i].l<j)head++;
//if(cmax(dp[i][j],l[head].sum+j*a[i].p))
//printf("%d %d %d %d\n",i,l[head].pos,j,dp[i][j]);
cmax(dp[i][j],l[head].sum+j*a[i].p);
}
if(j<a[i].s)
{
temp=dp[i-1][j]-j*a[i].p;
while(head<=tail&&l[tail].sum<=temp)tail--;
l[++tail].sum=temp;l[tail].pos=j;
}
}
}
printf("%d\n",dp[k][n]);
}
void init()
{
memset(dp,0,sizeof dp);ans=0;
}
int main()
{
file();
while(~scanf("%d%d",&n,&k))
{
init();
input();
work();
}
return 0;
}
hdu3157
#include<bits/stdc++.h>
using namespace std;
typedef int sign;
typedef long long ll;
#define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
#define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
const int N=50+5,M=200+5;
bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
template<typename T>T read()
{
T ans=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
return ans*f;
}
void file()
{
#ifndef ONLINE_JUDGE
freopen("3157.in","r",stdin);
freopen("3157.out","w",stdout);
#endif
}
struct edge
{
int v,nex,flow;
}e[M*N];
int n,m;
int head[N],tt;
int cur[N],dis[N],gap[N];
int sum[N],jud;
void add(int x,int y,int z)
{
++tt;e[tt].v=y;e[tt].flow=z;e[tt].nex=head[x];head[x]=tt;
++tt;e[tt].v=x;e[tt].flow=0;e[tt].nex=head[y];head[y]=tt;
}
void init()
{
tt=1;jud=0;
memset(head,0,sizeof head);
memset(sum,0,sizeof sum);
}
const int inf=0x3f3f3f3f;
char s1[N],s2[N];
int s,t,st,ed;
int deal(char *ss)
{
if(ss[0]=='+')return s;
else if(ss[0]=='-')return t;
int ans=0,len=strlen(ss);
For(i,0,len-1)ans=(ans<<3)+(ans<<1)+(ss[i]^48);
return ans;
}
void input()
{
int w,x,y;
s=n+1;t=s+1;st=t+1;ed=st+1;
For(i,1,m)
{
scanf("%s%s",s1,s2);
w=read<int>();
x=deal(s1);y=deal(s2);
add(x,y,inf);
sum[x]-=w;sum[y]+=w;
}
}
void build()
{
For(i,1,n+2)
{
if(sum[i]>0)add(st,i,sum[i]),jud+=sum[i];
else if(sum[i]<0)add(i,ed,-sum[i]);
}
add(t,s,inf);
}
void del()
{
For(u,st,ed)
{
for(register int i=head[u];i;i=e[i].nex)
{
e[i].flow=e[i^1].flow=0;
}
}
e[tt].flow=e[tt^1].flow=0;
}
int dfs(int u,int flow,int t1,int t2,int tot)
{
if(u==t2)return flow;
int v,f,res=flow;
for(register int &i=cur[u];i;i=e[i].nex)
{
v=e[i].v;
if(dis[u]==dis[v]+1&&e[i].flow)
{
f=dfs(v,min(e[i].flow,res),t1,t2,tot);
e[i].flow-=f;e[i^1].flow+=f;
if(!(res-=f))return flow;
}
}
if(!--gap[dis[u]])dis[t1]=tot;
++gap[++dis[u]];
return flow-res;
}
int isap(int t1,int t2,int tot)
{
memset(dis,0,sizeof dis);
memset(gap,0,sizeof gap);
int flow=0;
for(gap[0]=tot;dis[t1]<tot;)
{
memcpy(cur,head,sizeof cur);
flow+=dfs(t1,inf,t1,t2,tot);
}
return flow;
}
void work()
{
int flow;
if(isap(st,ed,n+4)!=jud)printf("impossible\n");
else
{
flow=e[tt].flow;
del();
printf("%d\n",flow-isap(t,s,n+2));
}
}
int main()
{
file();
while(scanf("%d%d",&n,&m))
{
if(!n&&!m)break;
init();
input();
build();
work();
}
return 0;
}