最大流 Dinic 算法实现的各种版本

http://blog.csdn.net/hqd_acm/article/details/6648290  解决hdu的爆栈问题


测试了一下迭代+前向星 交 hdu 4280 7093ms 感觉还不错。


//递归+矩阵版本


#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N=20;
const int INF=0x3f3f3f3f;
int s[N][N];//记录图的邻接矩阵
int d[N];//记录图中各点的层次
int n,m;
int min(int a,int b)
{
	return a<b?a:b;
}
bool bfs()
{
	queue<int>Q;
	memset(d,-1,sizeof(d));//此处初始化要特别注意,以上版本的初始化就存在很大问题
	d[1]=0;//如果处理不慎就很容易死循环
	Q.push(1);
	while(!Q.empty()){
		int v=Q.front();Q.pop();
		for(int i=1;i<=n;i++){
			if(d[i]==-1&&s[v][i]){//此处应是s[v][i]!=0,而不是以上版本中的s[v][i]>0,因为dfs是可能会走错,这样可以对其进行修正。
				d[i]=d[v]+1;
				Q.push(i);
			}
		}
	}
	return d[n]!=-1;
}
int dfs(int v,int cur_flow)
{
	int dt=cur_flow;
	if(v==n)return cur_flow;
	for(int i=1;i<=n;i++){
		if(s[v][i]>0&&d[v]+1==d[i]){
			int flow=dfs(i,min(dt,s[v][i]));//在下一层中继续搜路,直到终点
			s[v][i]-=flow;
			s[i][v]+=flow;
			dt-=flow;//找到一条路,存起来
		}
	}
	return cur_flow-dt;//从这一点可以流出多少流量
}
int dinic()
{
	int cur_flow,ans=0;
	while(bfs()){//一次bfs可以找到几条增广路
		while(cur_flow=dfs(1,INF))
			ans+=cur_flow;
	}
	return ans;
}
int main()
{
	int t,i,cas=0,u,v,w;
	scanf("%d",&t);
	while(t--){
		memset(s,0,sizeof(s));
		scanf("%d %d",&n,&m);
		for(i=1;i<=m;i++){
			scanf("%d %d %d",&u,&v,&w);
			if(u==v)continue;
			s[u][v]+=w;
		}
		printf("Case %d: %d\n",++cas,dinic());
	}
	return 0;
}

//递归+前向星版

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N=100010;
const int INF=0x3f3f3f3f;
const int MIN = -0xfffffff;
const int MAX = 0xfffffff;
//int s[N][N];//记录图的邻接矩阵
int d[N];//记录图中各点的层次
int n,m, S, T, num;
int head[N];

struct Edge{
    int s,e,v,next;
}edge[2*N];

void init(int a,int b,int c){
    edge[num].s = a;
    edge[num].e = b;
    edge[num].v = c;
    edge[num].next = head[a];
    head[a] = num++;
}

void add(int a,int b,int c){
    init(a,b,c);
    init(b,a,c);
}

int min(int a,int b)
{
	return a<b?a:b;
}
bool bfs()
{
	queue<int>Q;
	memset(d,-1,sizeof(d));//此处初始化要特别注意,以上版本的初始化就存在很大问题
	d[S]=0;//如果处理不慎就很容易死循环
	Q.push(S);
	while(!Q.empty()){
		int v=Q.front();Q.pop();
		for(int i=head[v];i != -1;i = edge[i].next){
		    int u = edge[i].e;
			if(d[u]==-1&&edge[i].v>0){//此处应是s[v][i]!=0,而不是以上版本中的s[v][i]>0,因为dfs是可能会走错,这样可以对其进行修正。
				d[u]=d[v]+1;
				Q.push(u);
			}
		}
	}
	return d[T]!=-1;
}

int dfs(int v,int cur_flow)
{
	int dt=cur_flow;
	if(v==T)return cur_flow;
	for(int i=head[v];i != -1;i = edge[i].next){
	    int u = edge[i].e;
		if(edge[i].v>0&&d[v]+1==d[u]){
			int flow=dfs(u,min(dt,edge[i].v));//在下一层中继续搜路,直到终点
			edge[i].v -= flow;
			edge[i^1].v += flow;
			dt-=flow;//找到一条路,存起来
		}
	}
	//cout<<"1"<<endl;
	return cur_flow-dt;//从这一点可以流出多少流量
}
int dinic()
{
	int cur_flow,ans=0;
	while(bfs()){//一次bfs可以找到几条增广路
		while(cur_flow=dfs(S,INF))
			ans+=cur_flow;
	}
	return ans;
}
int main()
{
	int t,i,cas=0,u,v,w;
	scanf("%d",&t);
	while(t--){
	    scanf("%d%d",&n,&m);
		//memset(s,0,sizeof(s));
		int west=MAX,east=MIN,x,y;
		for(i= 1; i <= n; i++){
            scanf("%d%d",&x,&y);
            if(x<west)west = x, S = i;
            if(x>east)east = x, T = i;
		}
		num = 0;
		memset(head,-1,sizeof(head));
		for(i=1;i<=m;i++){
			scanf("%d%d%d",&u,&v,&w);
			if(u==v)continue;
			add(u,v,w);
		}
		//cout<<S<<"-"<<T<<endl;
		printf("%d\n",dinic());
	}
	return 0;
}

//迭代+前向星版 hdu 4280 代码


//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N=100010;
const int INF=0x3f3f3f3f;
const int MIN = -0xfffffff;
const int MAX = 0xfffffff;
//int s[N][N];//记录图的邻接矩阵
int d[N];//记录图中各点的层次
int n,m, S, T, num;
int head[N];

struct Edge{
    int s,e,v,next;
}edge[2*N];

int stack[N];
int cur_head[N];
int que[N];

void init(int a,int b,int c){
    edge[num].s = a;
    edge[num].e = b;
    edge[num].v = c;
    edge[num].next = head[a];
    head[a] = num++;
}

void add(int a,int b,int c){
    init(a,b,c);
    init(b,a,c);
}

int min(int a,int b)
{
	return a<b?a:b;
}
bool bfs()
{
	queue<int>Q;
	memset(d,-1,sizeof(d));//此处初始化要特别注意,以上版本的初始化就存在很大问题
	d[S]=0;//如果处理不慎就很容易死循环
	Q.push(S);
	while(!Q.empty()){
		int v=Q.front();Q.pop();
		for(int i=head[v];i != -1;i = edge[i].next){
		    int u = edge[i].e;
			if(d[u]==-1&&edge[i].v>0){//此处应是s[v][i]!=0,而不是以上版本中的s[v][i]>0,因为dfs是可能会走错,这样可以对其进行修正。
				d[u]=d[v]+1;
				Q.push(u);
			}
		}
	}
	return d[T]!=-1;
}
int BFS()
{
    int i;
    int front=0,real=0;
    memset(d,-1,sizeof(d));
    que[real++] = S;
    d[S] = 0;
    while(front != real)
    {
        int u = que[front++];
        front = front%N;
        for(i = head[u];i != -1;i = edge[i].next)
        {
            int v = edge[i].e;
            if(edge[i].v > 0 && d[v] == -1)
            {
                d[v] = d[u] + 1;
                que[real++] = v;
                real = real%N;
                if(v == T)
                    return 1;
            }
        }
    }
    return 0;
}

int dfs(int v,int cur_flow)
{
	int dt=cur_flow;
	if(v==T)return cur_flow;
	for(int i=head[v];i != -1;i = edge[i].next){
	    int u = edge[i].e;
		if(edge[i].v>0&&d[v]+1==d[u]){
			int flow=dfs(u,min(dt,edge[i].v));//在下一层中继续搜路,直到终点
			edge[i].v -= flow;
			edge[i^1].v += flow;
			dt-=flow;//找到一条路,存起来
		}
	}
	//cout<<"1"<<endl;
	return cur_flow-dt;//从这一点可以流出多少流量
}

int find_max_flow(){
    int cur = S;
    int max_flow = 0, limit;
    int top = 0;
    memcpy(cur_head,head,sizeof(head));

    while(1){
        if(cur == T){
            limit = MAX;
            int back;
            for(int i = 0; i < top; i++){
                if(edge[stack[i]].v < limit){
                    limit = edge[stack[i]].v;
                    back = i;
                }
            }
            for(int i = 0; i < top; i++){
                edge[stack[i]].v -= limit;
                edge[stack[i]^1].v += limit;
            }
            max_flow += limit;
            top = back;
            cur = edge[stack[top]].s;
        }
        for(int i = cur_head[cur]; i != -1; i = cur_head[cur] = edge[i].next){
            if(edge[i].v != 0 && d[cur] == d[edge[i].e] - 1){
                break;
            }
            //cout<<"!"<<endl;
        }
        if(cur_head[cur] != -1){
            stack[top++] = cur_head[cur];
            cur = edge[cur_head[cur]].e;
        }
        else {
            if(top == 0){
                break;
            }
            d[cur] = -1;
            cur = edge[stack[--top]].s;
        }
        //cout<<"!"<<endl;
    }//cout<<"!"<<endl;
    return max_flow;
}

int dinic()
{
	int cur_flow,ans=0;
	while(BFS()){//一次bfs可以找到几条增广路
		while(cur_flow=find_max_flow())
			ans+=cur_flow;
	}
	return ans;
}
int main()
{
	int t,i,cas=0,u,v,w;
	scanf("%d",&t);
	while(t--){
	    scanf("%d%d",&n,&m);
		//memset(s,0,sizeof(s));
		int west=MAX,east=MIN,x,y;
		for(i= 1; i <= n; i++){
            scanf("%d%d",&x,&y);
            if(x<west)west = x, S = i;
            if(x>east)east = x, T = i;
		}
		num = 0;
		memset(head,-1,sizeof(head));
		for(i=1;i<=m;i++){
			scanf("%d%d%d",&u,&v,&w);
			if(u==v)continue;
			add(u,v,w);
		}
		//cout<<S<<"-"<<T<<endl;
		printf("%d\n",dinic());
	}
	return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值