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

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

被折叠的 条评论
为什么被折叠?



