经典的最大流题POJ1273

百度文库花了5分下的 可怜 不过确实是自己需要的东西 吐舌头
经典的最大流题 POJ1273

——其他练习题 POJ3436 

题意描述:

现在有m个池塘(1m开始编号,1为源点,m为汇点),n条水渠,给出这n条水渠所连接的池塘和所能流过的水量,求水渠中所能流过的水的最大容量.一道基础的最大流题目。http://poj.org/problem?id=1273

参考数据:

输入:

5 4

1 2 40

1 4 20

2 4 20

2 3 30

3 4 10

输出:

50

程序实现:

增广路算法Edmonds_Karp

//poj1273_Ek.cpp
#include<iostream>
#include<queue>
using namespace std;
const int N=201;
const int INF=99999999;
int n,m,sum,s,t;//s,t为始点和终点
int flow[N][N],cap[N][N],a[N],p[N];
//分别为:flow[u][v]为<u,v>流量、cap[u][v]为<u,v>容量、a[i]表示源点s到节点i的路径上的最小残留量、p[i]记录i的前驱
int min(int a,int b)
{
return a<=b?a:b;
}
void Edmonds_Karp()
{
int i,u,v;
queue<int>q;//队列,用bfs找增广路
while(1)
{
   memset(a,0,sizeof(a));//每找一次,初始化一次
   a[s]=INF;
   q.push(s);//源点入队
   while(!q.empty())
   {
    u=q.front();
    q.pop();
    for(v=1;v<=m;v++)
    {
     if(!a[v]&&flow[u][v]<cap[u][v])
     {
      p[v]=u;
      q.push(v);
      a[v]=min(a[u],cap[u][v]-flow[u][v]);//s-v路径上的最小残量
     }
    }
   }
   if(a[m]==0)//找不到增广路,则当前流已经是最大流
    break;
   sum+=a[m];//流加上
   for(i=m;i!=s;i=p[i])// //从汇点顺着这条增广路往回走
   {
    flow[p[i]][i]+=a[m];//更新正向流量
    flow[i][p[i]]-=a[m];//更新反向流量
   }
}
printf("%d\n",sum);
}
int main()
{
//freopen("in.txt","r",stdin);
int v,u,w;
    while(scanf("%d%d",&n,&m)!=EOF)
{
   s=1;//从1开始
   t=m;//m为汇点
   sum=0;//记录最大流量
   memset(flow,0,sizeof(flow));//初始化
   memset(cap,0,sizeof(cap));
   while(n--)
   {
    scanf("%d%d%d",&u,&v,&w);
    cap[u][v]+=w;//注意图中可能出现相同的边
   }
   Edmonds_Karp();
}
return 0;
}



空间优化: poj1273_Ek_youhua.cpp

在程序实现的时候,我们通常只是用一个cap数组来记录容量,而不记录流量,当流量+1的时候,我们可以通过容量-1来实现,以方便程序的实现。正向用cap[u][v],则反向用cap[v][u]表示。

#include<iostream>
#include<queue>
using namespace std;
const int N=201;
const int INF=99999999;
int n,m,sum,s,t,w;//s,t为始点和终点
int cap[N][N],a[N],p[N];
int min(int a,int b)
{
return a<=b?a:b;
}
void Edmonds_Karp()
{
int i,u,v;
queue<int>q;//队列,用bfs找增广路
while(1)
{
   memset(a,0,sizeof(a));//每找一次,初始化一次
   a[s]=INF;
   q.push(s);//源点入队
   while(!q.empty())
   {
    u=q.front();
    q.pop();
    for(v=1;v<=m;v++)
    {
     if(!a[v]&&cap[u][v]>0)
     {
      p[v]=u;
      q.push(v);
      a[v]=min(a[u],cap[u][v]);//s-v路径上的最小残量
     }
    }
   }
   if(a[m]==0)//找不到增广路,则当前流已经是最大流
    break;
   sum+=a[m];//流加上
   for(i=m;i!=s;i=p[i])// //从汇点顺着这条增广路往回走
   {
    cap[p[i]][i]-=a[m];//更新正向流量
    cap[i][p[i]]+=a[m];//更新反向流量
   }
}
printf("%d\n",sum);
}
int main()
{
// freopen("in.txt","r",stdin);
int v,u;
    while(scanf("%d%d",&n,&m)!=EOF)
{
   s=1;//从1开始
   t=m;//m为汇点
   sum=0;//记录最大流量
   memset(cap,0,sizeof(cap));//初始化
   while(n--)
   {
    scanf("%d%d%d",&u,&v,&w);
    cap[u][v]+=w;//注意图中可能出现相同的边
   }
   Edmonds_Karp();
}
return 0;
}


Dinic邻接矩阵实现:poj1273_Dinic.cpp


#include <cstdio> 
 #include <cstring> 
 #include <cstdlib> 
 #include <iostream> 
 #define min(x,y) ((x<y)?(x):(y)) 
 using namespace std; 
 const int MAX=0x5fffffff;// 
 int tab[250][250];//邻接矩阵  
 int dis[250];//距源点距离,分层图  
 int q[2000],h,r;//BFS队列 ,首,尾  
 int N,M,ANS;//N:点数;M,边数  
 int BFS() 
 { int i,j; 
 memset(dis,0xff,sizeof(dis));//以-1填充  
 dis[1]=0; 
 h=0;r=1; 
 q[1]=1; 
 while (h<r) 
 { 
 j=q[++h]; 
 for (i=1;i<=N;i++) 
 if (dis[i]<0 && tab[j][i]>0) 
 { 
 dis[i]=dis[j]+1;  
 q[++r]=i; 
 } 
 } 
 if (dis[N]>0) 
 return 1; 
 else 
 return 0;//汇点的DIS小于零,表明BFS不到汇点  
 } 
 //Find代表一次增广,函数返回本次增广的流量,返回0表示无法增广  
 int find(int x,int low)//Low是源点到现在最窄的(剩余流量最小)的边的剩余流量 
 { 
 int i,a=0; 
 if (x==N)return low;//是汇点  
 for (i=1;i<=N;i++) 
 if (tab[x][i] >0 //联通  
 && dis[i]==dis[x]+1 //是分层图的下一层  
 &&(a=find(i,min(low,tab[x][i]))))//能到汇点(a <> 0)  
 { 
 tab[x][i]-=a; 
 tab[i][x]+=a; 
 return a; 
 } 
 return 0; 
   } 
 int main() 
 { 
 //freopen("ditch.in" ,"r",stdin ); 
 //freopen("ditch.out","w",stdout); 
 int i,j,f,t,flow,tans; 
 while (scanf("%d%d",&M,&N)!=EOF){ 
 memset(tab,0,sizeof(tab)); 
 for (i=1;i<=M;i++) 
 { 
 scanf("%d%d%d",&f,&t,&flow); 
 tab[f][t]+=flow; 
 } 
 // 
 ANS=0; 
 while (BFS())//要不停地建立分层图,如果BFS不到汇点才结束  
 { 
 while(tans=find(1,0x7fffffff))ANS+=tans;//一次BFS要不停地找增广路,直到找不到为止  
 } 
 printf("%d\n",ANS); 
 } 
  //system("pause"); 
 }

Dinic邻接表实现poj1273_dinic.cpp

//#define LOCAL
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;

#define MAXN 210
#define INF 0x3f3f3f3f

struct Edge
{
	int st, ed;
	int c;
	int next;
}edge[MAXN << 1];

int n, m;
int s, t;
int ans;
int e = 0; 
int head[MAXN];
int d[MAXN];

int min(int a, int b)
{
	return a < b ? a : b;
}

void init()
{
	int i, j;
	int a, b, c; 
	s = 1;
	t = m;
	e = 0;
	ans = 0;
	memset(head, -1, sizeof(head));
	for(i = 1; i <= n; i++)
	{
		scanf("%d%d%d", &a, &b, &c);
		edge[e].st = a;
		edge[e].ed = b;
		edge[e].c = c;
		edge[e].next = head[a];
		head[a]= e++;
		edge[e].st = b;
		edge[e].ed = a;
		edge[e].next = head[b];
		head[b] = e++;
	}
}

int bfs()
{
	memset(d, -1, sizeof(d));
	queue<int> q;
	d[s] = 0;
	q.push(s);
	int i;
	int cur;
	while(!q.empty())
	{
		cur = q.front();
		q.pop();
		for(i = head[cur]; i != -1; i = edge[i].next)
		{
			if(d[edge[i].ed] == -1 && edge[i].c > 0)
			{
				d[edge[i].ed] = d[cur] + 1; 
				q.push(edge[i].ed);
			}	
		}
	}
	if(d[t] < 0)
		return 0;
	return 1;
}

int dinic(int x, int flow)
{
	if(x == t)
		return flow;
	int i, a;
	for(i = head[x]; i != -1; i = edge[i].next)
	{
		if(d[edge[i].ed] == d[x] + 1 && edge[i].c > 0 && (a = dinic(edge[i].ed, min(flow, edge[i].c))))
		{
			edge[i].c -= a;
			edge[i ^ 1].c += a;
			return a;	
		}
	}
	return 0;
}

void solve()
{
	while(scanf("%d%d", &n, &m) != EOF)
	{
		init();
		while(bfs())
		{
			int increment;
			increment = dinic(1, INF);
				ans +=  increment; 
		}
		printf("%d\n", ans);
	}
}

int main()
{
#ifdef LOCAL
	freopen("poj1273.txt", "r", stdin);
	// freopen(".txt", "w", stdout);
#endif
	solve();
	return 0;
}


SAP实现:poj1273_SAP.cpp

/* 

编者感悟:

sap学了很长时间,一直不敢下手写,结果就是不写永远不会真正的理解算法的含义,sap理论很多算法书上都有讲解,但我还是建议看数学专业 图论的书,比如 《有向图的理论,算法及应用》,这本书的内容非常棒,相信看过的都知道吧,比其他算法书上讲的透多了。
SAP有个优化就是 当出现断链时,就可以直接退出,还有个优化是当前弧的优化,这两个优化只需要一句话+一个数组就解决了,相当实惠,好的ISAP执行的效率真的非常高,我写的ISAP用的是链式前向星法表示。
这个就算是模板了吧,虽然写的不是很好。。

*/

 

#include<iostream>
#include<cstdio>
#include<memory.h>
#include<cmath>
using namespace std;
#define MAXN 500
#define MAXE 40000
#define INF 0x7fffffff
long ne,nv,tmp,s,t,index;
struct Edge{
    long next,pair;
    long v,cap,flow;
}edge[MAXE];
long net[MAXN];
long ISAP()
{
    long numb[MAXN],dist[MAXN],curedge[MAXN],pre[MAXN];
    long cur_flow,max_flow,u,tmp,neck,i;
    memset(dist,0,sizeof(dist));
    memset(numb,0,sizeof(numb));
    memset(pre,-1,sizeof(pre));
    for(i = 1 ; i <= nv ; ++i)
        curedge[i] = net[i];
    numb[nv] = nv;
    max_flow = 0;
    u = s;
    while(dist[s] < nv)
    {
        /* first , check if has augmemt flow */
        if(u == t)
        {
            cur_flow = INF;
            for(i = s; i != t;i = edge[curedge[i]].v) 
            {  
                if(cur_flow > edge[curedge[i]].cap)
                {
                    neck = i;
                    cur_flow = edge[curedge[i]].cap;
                }
            }
            for(i = s; i != t; i = edge[curedge[i]].v)
            {
                tmp = curedge[i];
                edge[tmp].cap -= cur_flow;
                edge[tmp].flow += cur_flow;
                tmp = edge[tmp].pair;
                edge[tmp].cap += cur_flow;
                edge[tmp].flow -= cur_flow;
            }
            max_flow += cur_flow;
            u = neck;
        }
        /* if .... else ... */
        for(i = curedge[u]; i != -1; i = edge[i].next)
            if(edge[i].cap > 0 && dist[u] == dist[edge[i].v]+1)
                break;
        if(i != -1)
        {
            curedge[u] = i;
            pre[edge[i].v] = u;
            u = edge[i].v;
        }else{
            if(0 == --numb[dist[u]]) break;
            curedge[u] = net[u];
            for(tmp = nv,i = net[u]; i != -1; i = edge[i].next)
                if(edge[i].cap > 0)
                    tmp = tmp<dist[edge[i].v]?tmp:dist[edge[i].v];
            dist[u] = tmp + 1;
            ++numb[dist[u]];
            if(u != s) u = pre[u];
        }
    }
    
    return max_flow;
}
int main() {
    long i,j,np,nc,m,n;
    long a,b,val;
    long g[MAXN][MAXN];
    while(scanf("%d%d",&ne,&nv)!=EOF)
    {
        s = 1;
        t = nv;
        memset(g,0,sizeof(g));
        memset(net,-1,sizeof(net));
        for(i=0;i<ne;++i)
        {
            scanf("%ld%ld%ld",&a,&b,&val);
            g[a][b] += val;
         }
         for(i=1;i<=nv;++i)
             for(j = i; j <= nv;++j)
                 if(g[i][j]||g[j][i])
                 {
                     edge[index].next = net[i];
                     edge[index].v = j;
                     edge[index].cap = g[i][j];
                     edge[index].flow = 0;
                     edge[index].pair = index+1;
                     net[i] = index++;
                     edge[index].next = net[j];
                     edge[index].v = i;
                     edge[index].cap = g[j][i];
                     edge[index].flow = 0;
                     edge[index].pair = index-1;
                     net[j] = index++;
                 }
        printf("%ld\n",ISAP());
    }
    return 0;
}


你可能感兴趣的:(算法,优化,百度,SAP,iostream,pair)