求最大流问题

the reason of failure:

1、pre[i]=u而不是pre[u]=i

复杂度O(m*2n)

就是从第一个点开始找能到目的地点的这条线,然后在这条线找出最小的容量m,

然后将这条线上的所有边都减去m,然后反向+m,

再重复找从第一个点能到目的地点的路径,直到找不到路径。

输入样例:

5 4
1 2 1
1 3 1
2 3 1
3 4 1
2 4 1

事实上,当我们第二次的增广路走3-2这条反向边的时候,就相当于把2-3这条正向边已经是用了的流量给”退”了回去,不走2-3这条路,而改走从2点出发的其他的路也就是2-4。(有人问如果这里没有2-4怎么办,这时假如没有2-4这条路的话,最终这条增广路也不会存在,因为他根本不能走到汇点)同时本来在3-4上的流量由1-3-4这条路来”接管”。而最终2-3这条路正向流量1,反向流量1,等于没有流量。(也就是这条退回去的路其实可以不用走这两次也能达到终点)

代码:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <queue>
using namespace std;
int map1[500][500];
int pre[500];
bool walked[500];
int m;
int dfs(int a,int b){
    queue<int>qq;
    qq.push(a);
    int i;
    memset(walked,0,sizeof(walked));
    memset(pre,-1,sizeof(pre));
    pre[a]=a;
    int u;
    while(!qq.empty()){
          //  cout << 666 <<endl;
        u=qq.front();qq.pop();
        for(i=1;i<=m;i++)
            if(map1[u][i]>0&&!walked[i]){
                walked[i]=1;
                pre[i]=u;  //i的pre是u而不是u的pre是i
                qq.push(i);
                if(i==b)return true; //意思为能从a走到b
            }
    }
    return false;
}
int result(int a,int b){
    int g2=0,i;
    while(dfs(a,b)){
        int g1=99999;
        for(i=b;i!=a;i=pre[i]){
            g1=min(map1[pre[i]][i],g1);
        }
        for(i=b;i!=a;i=pre[i]){
            map1[pre[i]][i]-=g1;
            map1[i][pre[i]]+=g1;
        }
        g2+=g1;
    }
    return g2;
}
int main(){
    freopen("in.txt","r",stdin);
    int i,j,k,l,f1,f2,f3,t1,t2,t3;
    int n;
    memset(map1,0,sizeof(map1));
    cin >> n>>m;// 表明有n条边,有m个图
    for(i=0;i<n;i++){
        cin >> t1>> t2 >>t3;
    map1[t1][t2]+=t3;
    }
    printf("%d",result(1,m));
    return 0;
}

复习了一遍最大流,其实就是搜索找增广,找到以后g2+通过pre这条增广的最小流量的边,也就是这个增广可以走的流量,然后cup正向-,逆向+。

#include <queue>
#include<iostream>
#include<stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <ctime> 
#include <queue>
using namespace std;
int const maxn=5e4+7;
struct ttt{
	int l,r,m;
};
ttt tree[maxn*4];
int map1[550][550];
int cup[550][550];
int pre[550];
int vis[550];
int n;
int dfs(int a,int b){
	memset(vis,0,sizeof(vis));
	memset(pre,-1,sizeof(pre));
	queue<int>qq;
	qq.push(a);
	int u;
	while(!qq.empty()){ //只用判断是否可以走 
		u=qq.front();qq.pop();
		for(int i=1;i<=n;i++)
			if(vis[i]==0&&cup[u][i]>0){
				pre[i]=u;vis[i]=1;
				qq.push(i);
				if(i==b)return true;
			}
	}
	return false;
}
int result(int a,int b){
	int g2=0;
	while(dfs(a,b)){ //从a开始dfs向b,直到不能dfs 
		int g1=1e9+7;
	//	cout <<a <<"到" <<b << endl;
		for(int i=b;i!=a;i=pre[i])
		g1=min(g1,cup[pre[i]][i]);
		for(int i=b;i!=a;i=pre[i]){
			cup[pre[i]][i]-=g1;
			cup[i][pre[i]]+=g1;
		}
		g2+=g1;    //g2是最大流 
	}
	return g2;
}
int main(){
	int i,j,k,f1,f2,f3,f4,t1,t2,t3,t4,m;
	freopen("in.txt","r",stdin);
	cin >> m>> n;
	for(i=1;i<=m;i++){
		cin >> t1>>t2>>t3;
		cup[t1][t2]=t3;
	}
	cout << result(1,n) << endl;
	return 0;
}

更快的模版Dinic

#include<cstdio>
 #include<cstring>
 #include<queue>
 #include<cmath>
 using namespace std;
 const int Ni = 210;
 const int MAX = 1<<26;
 struct Edge{
     int u,v,c;
     int next;
 }edge[20*Ni];
 int n,m;
 int edn;//边数
 int p[Ni];//父亲
 int d[Ni];
 int sp,tp;//原点,汇点

 void addedge(int u,int v,int c)
 {
     edge[edn].u=u; edge[edn].v=v; edge[edn].c=c;
     edge[edn].next=p[u]; p[u]=edn++;

     edge[edn].u=v; edge[edn].v=u; edge[edn].c=0;
     edge[edn].next=p[v]; p[v]=edn++;
 }
 int bfs()
 {
     queue <int> q;
     memset(d,-1,sizeof(d));
     d[sp]=0;
     q.push(sp);
     while(!q.empty())
     {
         int cur=q.front();
         q.pop();
         for(int i=p[cur];i!=-1;i=edge[i].next)
         {
             int u=edge[i].v;
             if(d[u]==-1 && edge[i].c>0)
             {
                 d[u]=d[cur]+1;
                 q.push(u);
             }
         }
     }
     return d[tp] != -1;
 }
 int dfs(int a,int b)
 {
     int r=0;
     if(a==tp)return b;
     for(int i=p[a];i!=-1 && r<b;i=edge[i].next)
     {
         int u=edge[i].v;
         if(edge[i].c>0 && d[u]==d[a]+1)
         {
             int x=min(edge[i].c,b-r);
             x=dfs(u,x);
             r+=x;
             edge[i].c-=x;
             edge[i^1].c+=x;
         }
     }
     if(!r)d[a]=-2;
     return r;
 }

 int dinic(int sp,int tp)
 {
     int total=0,t;
     while(bfs())
     {
         while(t=dfs(sp,MAX))
         total+=t;
     }
     return total;
 }
 int main()
 {
 	freopen("in.txt","r",stdin);
     int i,u,v,c;
     while(~scanf("%d%d",&m,&n))
     {
         edn=0;//初始化
         memset(p,-1,sizeof(p));
         sp=1;tp=n;
         for(i=0;i<m;i++)
         {
             scanf("%d%d%d",&u,&v,&c);
             addedge(u,v,c);
         }
         printf("%d\n",dinic(sp,tp));
     }
     return 0;
 }


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值