第一次做网络流题目,写个报告巩固一下哈。
5 4 1 2 40 1 4 20 2 4 20 2 3 30 3 4 10
50最基础网络流,没什么好写的,写注释吧。#include<iostream> #include<queue> using namespace std; struct unit{ int v; int adj; unit(){} unit(int xv,int xa){ v=xv;adj=xa; } }; struct Link{ int s,e; int v; }; queue<unit> path; int f_min(int x,int y){ return x<y?x:y; } int M,N; int map[201][201],now[201][201]; void get_link(){ int i,ts,te; int tv; memset(map,-1,sizeof(map)); memset(now,0,sizeof(now)); for(i=0;i<M;i++){ scanf("%d%d%d",&ts,&te,&tv); //如果边有重复就加上去,否则直接赋值 if(map[ts][te]==-1)map[ts][te]=tv; else map[ts][te]+=tv; } } bool mark[201]; int pre[201]; int bfs(){ memset(mark,0,sizeof(mark)); mark[1]=1; path.push(unit(1,-1));//先推入点1,-1表示未调节 int i; unit x; while(path.size()){ for(i=2;i<=N;i++){ x=path.front(); if(!mark[i]&&map[x.v][i]!=-1){//如果有正边 if(now[x.v][i]<map[x.v][i]){//而且能增加 if(x.adj==-1||x.adj>map[x.v][i]-now[x.v][i]) x.adj=map[x.v][i]-now[x.v][i];//调节值取小者,原来没调节则取新者 path.push(unit(i,x.adj));mark[i]=1;pre[i]=x.v;//第三句记录前一点 } } if(!mark[i]&&map[i][x.v]!=-1){//如果有负边 if(now[i][x.v]>0){//而且能减少 if(x.adj==-1||x.adj>now[i][x.v]) x.adj=now[i][x.v]; path.push(unit(i,x.adj));mark[i]=1;pre[i]=x.v; } } if(mark[N])return x.adj;//如果N被标记了,那肯定是刚推进去的那个,返回最新那个调节值即可 } path.pop(); } return 0; } bool broader(){ int adj=bfs(),i;//广搜,并返回要调节的值 while(!path.empty())path.pop();//不清空是万万不能的 if(!adj)return 0;//无法调节,返回0 for(i=N;i!=1;i=pre[i]){ if(map[pre[i]][i]==-1)now[i][pre[i]]-=adj;//负向边减调节值 else now[pre[i]][i]+=adj;//正向边加调节值 } return 1; } void run(){ int i; while(broader());//不能增广时退出 int o=0; for(i=2;i<=N;i++){ o+=now[1][i];//把从1出发的各边现有值加上 } printf("%d/n",o); } int main(){ while(scanf("%d%d",&M,&N)!=EOF){ get_link(); run(); } return 0; }还是再加一点吧,加深印象。//--------------------------------------基本思路就是先广搜出一条路来,这条路上的正向边要还能增加,负向边要还能减少,称为增广路径。同时要取得一个调节值a,为min(正向边的最小增加值,负向边的最小减少值)。然后对这条路上的正向边加a,负向边减a,如此做可保证当前网络图仍是一个可行流,同时能增加最大流量。这个好理解。//--------------------------------------
然后直到搜不到增广路,则当前图必定已经是最大流了。由第一段易证必要条件。
那来证充分条件,证它逆否命题:若当前图还不是最大流,必定能找到一条增广路。
若当前图还不是最大流,那从1出发到某点a肯定有一条边还得增加。这条边增加了么,从a出发肯定得有条负向边减少或者有条正向边增加。然后一直下去总得停吧?那中间的点出入度都是0不能变的,起点又没有入度,只能到终点才停了,那这就是一条增广路。
over