题目描述 Description
给定一张航空图,图中顶点代表城市,边代表 2 城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。
(1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东
向西飞回起点(可途经若干城市)。
(2)除起点城市外,任何城市只能访问 1 次。
对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。
输入描述 Input Description
第 1 行有 2 个正整数 N 和 V,N 表示城市数,N<100,V 表示直飞航线数。
接下来的 N 行中每一行是一个城市名,可乘飞机访问这些城市。城市名出现的顺序是从西向东。也就是说,设 i,j 是城市表列中城市出现的顺序,当 i>j 时,表示城市 i 在城市 j 的东边,而且不会有 2 个城市在同一条经线上。城市名是一个长度不超过15 的字符串,串中的字符可以是字母或阿拉伯数字。例如,AGR34 或 BEL4。
再接下来的 V 行中,每行有 2 个城市名,中间用空格隔开,如 city1 city2 表示city1到 city2 有一条直通航线,从 city2 到 city1 也有一条直通航线。
输出描述 Output Description
第 1 行是旅行路线中所访问的城市总数 M。接下来的 M+1 行是旅行路线的城市名,每行写 1 个城市名。首先是出发城市名,然后按访问顺序列出其它城市名。注意,最后 1 行(终点城市)的城市名必然是出发城市名。如果问题无解,则输出“No Solution!”。
样例输入 Sample Input
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
样例输出 Sample Output
7
Vancouver
Edmonton
Montreal
Halifax
Toronto
Winnipeg
Calgary
Vancouver
数据范围及提示 Data Size & Hint
//O(Kn^2m)
//如果要求最大费用的话 只需在加边的时候加-的边 输出时输出-ans即可
#pragma comment(linker,"/STACK:102400000,102400000")
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <string>
#include <math.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
typedef long long ll; //记得必要的时候改成无符号
const int maxn=505;
const int maxm=1000005;
const int INF=1000000000;
struct EdgeNode
{
int from;
int to;
int flow;
int cost;
int next;
}edge[maxm];
int head[maxn],cnt;
void add(int x,int y,int z,int c)
{
edge[cnt].from=x;edge[cnt].to=y;edge[cnt].flow=z;edge[cnt].cost=c;edge[cnt].next=head[x];head[x]=cnt++;
edge[cnt].from=y;edge[cnt].to=x;edge[cnt].flow=0;edge[cnt].cost=-c;edge[cnt].next=head[y];head[y]=cnt++;
}
void init()
{
cnt=0;
memset(head,-1,sizeof(head));
}
int S,T,n,m;
int d[maxn],in[maxn],pre[maxn];
queue<int>Q;
bool spfa(int S,int T)
{
int u,v,f,c;
while(!Q.empty())Q.pop();
memset(in,0,sizeof(in));
for(int i=0;i<=n;i++)d[i]=INF;
d[S]=0;
Q.push(S);
while(!Q.empty())
{
u=Q.front(); Q.pop(); in[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next){
v=edge[i].to; f=edge[i].flow; c=edge[i].cost;
if(f&&d[u]+c<d[v]){
d[v]=d[u]+c; pre[v]=i;
if(!in[v]){
in[v]=1;
Q.push(v);
}
}
}
}
if(d[T]==INF)return false;
return true;
}
int MCMF(int S,int T,int need=0)
{
int u;
int max_flow=0;
int min_cost=0;
while(spfa(S,T))
{
int flow=INF;
u=T;
while(u!=S){
flow=min(flow,edge[pre[u]].flow);
u=edge[pre[u]].from;
}
u=T; max_flow+=flow; min_cost+=d[T]*flow;
while(u!=S){
edge[pre[u]].flow-=flow;
edge[pre[u]^1].flow+=flow;
u=edge[pre[u]].from;
}
}
if(max_flow!=2) return -1;
return min_cost;
}
map<string,int>mp;
map<int,string>pm;
int chu[maxn],q1,q2,p[maxn];
int main()
{
char s[100],t[100];
string a,b;
int ans,i,x,y,N;
while(~scanf("%d%d",&n,&m))
{
ans=0;
mp.clear(); pm.clear();
for(i=1;i<=n;i++){
scanf("%s",s);
a=s;
mp[a]=++ans;
pm[ans]=a;
}
init(); S=1; T=n*2;
for(i=1;i<=n;i++){
if(i==1||i==n)add(i,i+n,2,-1);
else add(i,i+n,1,-1);
}
for(i=1;i<=m;i++){
scanf("%s%s",s,t);
a=s; b=t;
x=mp[a]; y=mp[b];
if(x>y)swap(x,y);
if(x==1&&y==n)add(x+n,y,2,0);
else add(x+n,y,1,0);
}
N=n;
n=T+1;
ans=MCMF(S,T);
if(ans==-1)printf("No Solution!\n");
else{
printf("%d\n",-ans-2);
q1=q2=-1;
memset(p,-1,sizeof(p));
for(i=0;i<cnt;i++){
x=edge[i].from; y=edge[i].to;
//printf(" %d %d %d\n",x,y,edge[i].flow);
if(edge[i].flow)continue;
if(x>N&&y<=N){
if(y==N){
if(q1==-1)q1=x-N;
else q2=x-N;
}
else p[y]=x-N;
}
}
ans=0;
int t=q1;
while(t!=-1){
chu[++ans]=t;
t=p[t];
}
for(i=ans;i>=1;i--)cout<<pm[chu[i]]<<endl;
cout<<pm[N]<<endl;
t=q2; ans=0;
while(t!=-1){
chu[++ans]=t;
t=p[t];
}
for(i=1;i<=ans;i++)cout<<pm[chu[i]]<<endl;
}
}
return 0;
}