「网络流 24 题」航空路线问题

题目描述

给定一张航空图,图中顶点代表城市,边代表两个城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。

  1. 从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。
  2. 除起点城市外,任何城市只能访问一次。

对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。

输入格式

第一行有两个正整数 NNN 和 VVVNNN 表示城市数,VVV 表示直飞航线数。
接下来的 NNN 行中每一行是一个城市名,可乘飞机访问这些城市。城市名出现的顺序是从西向东。也就是说,设 i,ji,ji,j 是城市表列中城市出现的位置次序,当 i>ji>ji>j 时,表示 城市 iii在城市 jjj 的东边,而且不会有两个城市在同一条经线上。城市名是一个长度不超过 151515 的字符串,串中的字符可以是大小写字母或阿拉伯数字。例如,AGR34\text{AGR34}AGR34 或 BEL4\text{BEL4}BEL4
再接下来的 VVV 行中,每行有两个城市名,中间用空格隔开,如 city1 city2\text{city1 city2}city1 city2 表示 city1\text{city1}city1 到 city2\text{city2}city2 有一条直通航线,从 city2\text{city2}city2 到 city1\text{city1}city1 也有一条直通航线。

输出格式

输出最佳航空旅行路线。
第一行是旅行路线中所访问的城市总数 MMM
接下来的 M+1M+1M+1 行是旅行路线的城市名,每行一个。首先是出发城市名,然后按访问顺序列出其它城市名。注意,最后一行(终点城市)的城市名必然是出发城市名。如果有多组最优解,输出任意一组均可;如果问题无解,则输出 No Solution!

样例
样例输入
8 9
Vancouver
Yellowknife
Edmonton
Calgary
Winnipeg
Toronto
Montreal
Halifax
Vancouver Edmonton
Vancouver Calgary
Calgary Winnipeg
Winnipeg Toronto
Toronto Halifax
Montreal Halifax
Edmonton Montreal
Edmonton Yellowknife
Edmonton Calgary
样例输出
7
Vancouver 
Edmonton 
Montreal
Halifax
Toronto 
Winnipeg
Calgary
Vancouver



最小费用最大流,重要的是路径的输出。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;
#define swap(a,b){int c;c=a,a=b,b=c;}
const int maxm = 10005;
const int INF = 1e9 + 7;
map<string, int>p;
struct node
{
	int u, v, flow, cost, next;
}edge[maxm];
int head[maxm], vis[maxm], pre[maxm], dis[maxm];
int cnt, n, m, s, t, ans = 0;
char str[105][25], ch[25], sh[25];
void init()
{
	cnt = 0, s = 0, t = n * 2 + 1;
	memset(head, -1, sizeof(head));
}
void add(int u, int v, int w, int cost)
{
	edge[cnt].u = u, edge[cnt].v = v;
	edge[cnt].flow = w, edge[cnt].cost = cost;
	edge[cnt].next = head[u], head[u] = cnt++;
	edge[cnt].u = v, edge[cnt].v = u;
	edge[cnt].flow = 0, edge[cnt].cost = -cost;
	edge[cnt].next = head[v], head[v] = cnt++;
}
int bfs()
{
	queue<int>q;
	for (int i = 0;i <= t;i++) dis[i] = INF;
	memset(pre, -1, sizeof(pre));
	q.push(s);
	dis[s] = 0;
	while (!q.empty())
	{
		int u = q.front();q.pop();
		for (int i = head[u];i != -1;i = edge[i].next)
		{
			int v = edge[i].v;
			if (dis[v] > dis[u] + edge[i].cost&&edge[i].flow)
			{
				dis[v] = dis[u] + edge[i].cost;
				pre[v] = i;
				q.push(v);
			}
		}
	}
	if (dis[t] == INF) return 0;
	return 1;
}
int MCMF()
{
	int minflow, flow = 0;
	while (bfs())
	{
		minflow = INF;
		for (int i = pre[t];i != -1;i = pre[edge[i].u])
			minflow = min(minflow, edge[i].flow);
		for (int i = pre[t];i != -1;i = pre[edge[i].u])
			edge[i].flow -= minflow, edge[i ^ 1].flow += minflow;
		ans -= minflow*dis[t], flow += minflow;
	}
	return flow;
}
void prin(int u, int n) 
{
	vis[u] = 1;
	for (int i = head[u], v;i != -1;i = edge[i].next)
	{
		if (!vis[v = edge[i].v] && ((!edge[i].flow && edge[i].cost <= 0) || (edge[i].flow&&edge[i].cost >= 0)))
		{
			prin(v, n);
			if (v <= n) puts(str[v]);
		}
	}
}
int main()
{
	int i, j, k, sum;
	scanf("%d%d", &n, &m);
	init();
	for (i = 1;i <= n;i++)
	{
		scanf("%s", str[i]);
		p[str[i]] = i;
		if (i == 1 || i == n) add(i, i + n, 2, 0);
		else add(i, i + n, 1, 0);
	}
	add(s, 1, 2, 0);
	add(n * 2, t, 2, 0);
	for (i = 1;i <= m;i++)
	{
		scanf("%s", ch);
		scanf("%s", sh);
		int a = p[ch], b = p[sh];
		if (a > b) swap(a, b);
		if (a == 1 && b == n) add(a + n, b, 2, -1);
		add(a + n, b, 1, -1);
	}
	if (MCMF() != 2) { printf("No Solution!\n");return 0; }
	printf("%s", str[1]);
	prin(1, n);
	puts(str[1]);
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值