今天的主要任务是看网络流的资料。虽然看了3个ppt和两个word以及一些例题,但是还是感觉不懂。这里先把概念贴一下。。。
by 某个dalao的博客:
网络流是指给定一个有向图,和两个点–源点S和汇点T,点之间有连边, 每条边有一个容量限制,可以看作水管,网络流就是指由S点流到T点的一个可行流。
最大流就是指所有可行流里面最大的流。
通俗的讲,就是由若干个运货点,一个是起点,一个是终点,有一些运货点由路相连,每条路有容量限制,走过那条路时运送的货物不能超过其中的容量限制,求最大流就是求从起点运送尽量多的货物到终点,到达终点的货物个数。
还是比较容易理解的。但是很快会发现,最难的还是建图。
有些题目直接构图点的数量或边的数量会非常大,会超时或爆内存,因此可以通过缩点来进行优化。即:
如果几个节点的来源完全相同,则可以把它们合成一个。
如果几个节点的去向完全相同,则可以把它们合成一个。
如果从u到v有一条容量为∞的边,并且v除了u以外没有别的流量来源,则可以把这它们合并成一个。
个人Dinic算法模板:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
#define rep(i,a,b) for(register int i=(a),iend=(b);i<=iend;++i)
inline int read()
{
register int c=getchar(),fg=1,sum=0;
while(c>'9'||c<'0') {if(c == '-')fg = -1;c=getchar();}
while(c<='9'&&c>='0'){sum=sum*10+c-'0';c=getchar();}
return fg*sum;
}
const int mx=100010;
const int inf=0x3f3f3f3f;
int n,m,t;
int he[mx],d[mx];
struct edge{
int v,nex;
int w;
}a[mx];
void init()
{
t=0;
memset(he,-1,sizeof(he));
}
void add(int u,int v,int w)
{
a[t].v=v;
a[t].nex=he[u];
a[t].w=w;
he[u]=t++;
}
int bfs()
{
memset(d,-1,sizeof(d));//zhu yi shi -1
queue<int> q;
q.push(n);
d[n]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=he[u];i!=-1;i=a[i].nex)
{
int v=a[i].v;
if(a[i^1].w&&d[v]==-1)
{
d[v]=d[u]+1;
q.push(v);
}
}
}
return d[1]!=-1;
}
int dfs(int x,int low)
{
if(x==n)return low;
int k;
for(int i=he[x];i!=-1;i=a[i].nex)
{
int v=a[i].v;
if(a[i].w&&d[v]==d[x]-1)
{
k=dfs(v,min(low,a[i].w));
if(k>0){
a[i].w-=k;
a[i^1].w+=k;
return k;
}
}
}
return 0;
}
int main()
{
int T,cas=1;
while(scanf("%d",&T)!=EOF)
{
while(T--)
{
scanf("%d%d",&n,&m);
init();
rep(i,1,m)
{
int x,y,z;
x=read(),y=read(),z=read();
add(x,y,z);
add(y,x,0);
}
int ans=0,k;
while(bfs())
{
k=dfs(1,inf);
ans+=k;
}
printf("Case %d: %d\n",cas++,ans);
}
}
return 0;
}
个人犯过的错误:
初始化一定不能错,搞清楚。是否添加源点和汇点,n相应的值要怎样变化,如果不需要添加,源点和汇点是哪两个。
比较常见的两种构图,一种是邻接矩阵,一种是链式前向星。
最后引用大牛的话:
虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。
加油!