最大流经典题--航线最优安排

本文介绍了一种解决最大流问题的算法——Dinic算法,并通过一个具体案例(成都旅行社国庆首都游的行程规划)来展示算法的应用过程。文章详细解释了Dinic算法的工作原理,包括使用BFS构建层次网络和DFS进行流量增广的过程。

题目描述

 国庆大假期间旅游非常火爆,机票早已订购一空。成都一家旅行社由于信誉好、服务好,所策划的国庆首都游的行情看好,要求参加的游客众多,游客甚至不惜多花机票钱辗转取道它地也愿参加此游。旅行社只好紧急电传他在全国各地的办事处要求协助解决此问题。很快,各办事处将其已订购机票的情况传到了总社。根据此资料,总社要作出计划,最多能将多少游客从成都送往北京以及如何取道转机。下面是各办事处已订购机票的详细情况表:

成都 重庆 武汉 上海 西安 郑州 沈阳 昆明 广州 北京
成都 10 5 15 8 12 10 30
重庆 5 6 15 25
武汉 10
上海 15 8
西安 8 6
郑州 14 8
沈阳 18
昆明 8 10
广州 8 2 6 10

题解

这个明显是最大流。这个表就是一个临界矩阵,i行j列的值就是从i到j的边的容量,建图跑dinic就行。源点是成都,汇点是北京。dinic是一次层次网络后多路同时增广,保证了效率,但这样不好记录方案。如果一次增广一条路径,就可以记下这条路径,完了就知道有多大的流量流过这条路径了。

代码

#include <iostream>
#include <queue>
#include<cstdio>
#include<cstring>
using namespace std;

const int INF = 0x7fffffff;
int V, E;
int level[205];
int Si, Ei, Ci;

struct Dinic
{
    int c;
    int f;
}edge[205][205];
int rec[205];
char city[12][20]={
    {},
    {"Chengdu"},
    {"Chongqing"},
    {"Wuhan"},
    {"Shanghai"},
    {"Xian"},
    {"Zhengzhou"},
    {"Shenyang"},
    {"Kunming"},
    {"Guangzhou"},
    {"Beijing"}
};
bool dinic_bfs()      //bfs方法构造层次网络
{
    queue<int> q;
    memset(level, 0, sizeof(level));
    q.push(1);
    level[1] = 1;
    int u, v;
    while (!q.empty()) {
        u = q.front();
        q.pop();
        for (v = 1; v <= E; v++) {
            if (!level[v] && edge[u][v].c>edge[u][v].f) {
                level[v] = level[u] + 1;
                q.push(v);
            }
        }
    }
    return level[E] != 0;                //question: so it must let the sink node is the Mth?/the way of yj is give the sink node's id
}

int dinic_dfs(int u, int cp) {           //use dfs to augment the flow
    int tmp = cp;
    int v, t;
    if (u == E)
        return cp;
    for (v = 1; v <= E&&tmp; v++) {
        if (level[u] + 1 == level[v]) {
            if (edge[u][v].c>edge[u][v].f) {
                t = dinic_dfs(v, min(tmp, edge[u][v].c - edge[u][v].f));
                edge[u][v].f += t;
                edge[v][u].f -= t;
                tmp -= t;
                if(t>0){
                    rec[u]=v;
                    break;//只增广一条路
                }
            }
        }
    }
    return cp - tmp;
}
int dinic() {
    int sum=0, tf=0;
    while (dinic_bfs()) {
        while (tf = dinic_dfs(1, INF)){
            sum += tf;
            printf("%s ",city[1]);
            for(int pp=rec[1];;pp=rec[pp]){
                printf("->%s ",city[pp]);
                if(pp==E)break;
            }
            printf("for %d people\n",tf);
        }
    }
    return sum;
}

int main() {
    scanf("%d",&E);
    memset(edge, 0, sizeof(edge));
    for(int i=1;i<E;i++){
        for(int j=1;j<=E;j++){
            scanf("%d",&edge[i][j].c);
        }
    }
    int ans = dinic();
    printf("%d\n", ans);
    
    return 0;
}

输入

把表格当成2位数组输入。

/*
10
0  10 5  15 8  0  0  12 10 30
0  0  5  0  6  0  0  15 0  25
0  0  0  10 0  0  0  0  0  0  
0  0  0  0  0  15 8  0  0  0  
0  0  0  8  0  6  0  0  0  0 
0  0  0  0  0  0  14 0  0  8  
0  0  0  0  0  0  0  0  0  18
0  0  0  0  0  8  0  0  0  10
0  0  0  8  2  0  6  0  0  10
*/

结果

在这里插入图片描述
如图,先给出了每种路线可以安排几个人飞。完了最后一共86个人能飞到北京。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值