題目描述 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;
}