[笔记] 网络流-最大流 POJ-1273\HDU-4240

1 篇文章 0 订阅
1 篇文章 0 订阅

[1] POJ-1273

题目:http://poj.org/problem?id=1273

最直接的最大流问题,用了Ford-Fulkerson方法,DFS随机搜索增广路.

算法原理参考:http://blog.csdn.net/smartxxyx/article/details/9293665

/***********************
*  POJ-1273
*  Ford-Fulkerson
***********************/
#include <stdio.h>
#include <string.h>

const int INF = (1<<31)-1;
int map[500][500];//邻接矩阵 
int fa[500];//记录父节点 
int vis[500];//DFS标记数组 

int dfs(int stap,int min);

int n,m;
int main(){
    
    while (scanf("%d%d",&m,&n)!=EOF){
        
        memset(map,0,sizeof(map));
        for (int i=1;i<=m;i++){
            int u,v,val;
            scanf("%d%d%d",&u,&v,&val);
            map[u][v] += val;//累加处理,防止重边 
        }
        
        int max_flow = 0;
        int temp;
        
        while (1){
            
            memset(vis,0,sizeof(vis));
            vis[1] = 1;
            for (int i=1;i<=n;i++) fa[i] = i;
            
            temp = dfs(1,INF);//从顶点[1]出发,在残留网络中DFS搜索一条增广路,返回路径的合法流量 
            if (temp == INF) break;//如果搜不到增广路则说明已经没有更大流量
            max_flow += temp;
            
            //更新残留网络,正向边减去temp,反向边加上temp 
            int p = n;
            while (p!=1){
                int fat = fa[p];
                map[fat][p] -= temp;
                map[p][fat] += temp;
                p = fat;
            }
            
        }
        printf("%d\n",max_flow);
    }
    return 0;
}

int dfs(int stap,int min){
    
    for (int i=1;i<=n;i++)//寻找stap所指向的一个子节点 
    if (!vis[i]&&map[stap][i]>0){
        
        vis[i] = 1;
        fa[i] = stap;
        
        if (map[stap][i]<min) min = map[stap][i];//保持流量合法 
        if (i==n) return min;//DFS出口 
        else{
            int temp = dfs(i,min);
            if (temp<min) min = temp;
        }
    }
    
    if (fa[n]!=n) return min;//fa[n]!=n 说明本次搜素成功地找到一条增广路 
    else return INF;
}

[2] HDU-4240

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4240

题意是求一个比值,[最大流]和[最大流量路径的流量]的比值.

本题用DFS找增广路时超时了,改用了BFS搜索增广路,但是时间效率仍然不高.

其实对算法的详细机制还没有很清楚,也还不清楚为什么BFS会比DFS快,慢慢体会

更高效的算法有DINIC和SAP等.

为了方便同时用了两个矩阵和邻接表

#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
const int INF = (1<<31)-1;
const int MAX = 1001;
int map[MAX][MAX];//记录残留网络
int org[MAX][MAX];//记录原图
int head[MAX];
int next[MAX*2];
int edge[MAX*2];
int fa[MAX];
int vis[MAX];//vis数组同时用作标记和记录源点到本节点的合法流量

int main(){
    
    int n,m,sta,end;
    int t,cases;
    scanf("%d",&t);
    while (t--){
        
        int u,v,val;
        scanf("%d%d%d%d%d",&cases,&n,&m,&sta,&end);
        sta++;end++;
        memset(map,0,sizeof(map));
        memset(org,0,sizeof(org));
        memset(head,0xff,sizeof(head));
        int cnt = 0;
        
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&u,&v,&val);
            map[u+1][v+1] += val;
            org[u+1][v+1] += val;
            
            cnt++;
            edge[cnt] = v+1;
            next[cnt] = head[u+1];
            head[u+1] = cnt;
            
            cnt++;
            edge[cnt] = u+1;
            next[cnt] = head[v+1];
            head[v+1] = cnt;
        }
        
        int max_flow = 0;
        int max_rot = 0;
        
        while (1){
            
            for (int i=1;i<=n;i++) fa[i] = i;
            memset(vis,0,sizeof(vis));
            vis[sta] = INF;
            queue<int> q;
            q.push(sta);

            while (!q.empty()){
                u = q.front();
                q.pop();

                for (int i=head[u];i!=-1;i=next[i]){
                    v = edge[i];
                    if (!vis[v]&&map[u][v]){
                        q.push(v);
                        fa[v] = u;
                        vis[v] = vis[u]<map[u][v] ? vis[u]:map[u][v];
                        if (v==end) break;
                    }
                }
                if (v==end) break;
            }
            
            if (vis[end]==0) break;
            max_flow += vis[end];
            int p = end;
            int rot_min = INF;
            while (p!=sta){
                int fat = fa[p];
                if (org[fat][p]<rot_min) rot_min = org[fat][p];
                map[fat][p] -= vis[end];
                map[p][fat] += vis[end];
                p = fat;
            }
            
            if (rot_min>max_rot) max_rot = rot_min;
        }
        
        double ans = ((double)max_flow)/((double)max_rot);
        printf("%d %.3lf\n",cases,ans);
        
    }
    
    return 0;
}

还是CSDN上看代码舒服.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值