题意:摘自NOCOW翻译(http://www.nocow.cn/index.php/Translate:USACO/tour)
描述
你赢得了一场航空公司举办的比赛,奖品是一张加拿大环游机票。旅行在这家航空公司开放的最西边的城市开始,然后一直自西向东旅行,直到你到达最东边的城市,再由东向西返回,直到你回到开始的城市。除了旅行开始的城市之外,每个城市只能访问一次,因为开始的城市必定要被访问两次(在旅行的开始和结束)。
当然不允许使用其他公司的航线或者用其他的交通工具。
给出这个航空公司开放的城市的列表,和两两城市之间的直达航线列表。找出能够访问尽可能多的城市的路线,这条路线必须满足上述条件,也就是从列表中的第一个城市开始旅行,访问到列表中最后一个城市之后再返回第一个城市。
[编辑]格式
PROGRAM NAME: tour
INPUT FORMAT
Line 1: 航空公司开放的城市数 N 和将要列出的直达航线的数量 V。N 是一个不大于 100 的正整数。V 是任意的正整数。
Lines 2..N+1: 每行包括一个航空公司开放的城市名称。城市名称按照自西向东排列。不会出现两个城市在同一条经线上的情况。每个城市的名称都 是一个字符串,最多15字节,由拉丁字母表上的字母组成;城市名称中没有空格。
Lines N+2..N+2+V-1: 每行包括两个城市名称(由上面列表中的城市名称组成),用一个空格分开。这样就表示两个城市之间的直达双程航线。
OUTPUT FORMAT
Line 1: 按照最佳路线访问的不同城市的数量 M。如果无法找到路线,输出 1。
[编辑]SAMPLE INPUT (file tour.in)
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 (file tour.out)
7
解题思路:
- 参考NOCOW“动态规划”,见下
-
把返回的路线反向,那么整条路线就变成了两条不相交的从起点到终点的路线。这样我们可以用DP解决
-
状态设定:f[i,j] 为假定的甲乙两人,甲走到第i个城市,乙走到第j个城市时,两人走过的城市数目的和
-
初始状态:f[1,1]=1
-
状态转移方程:f[j,i]=f[i,j]=max{f[i,k]+1}(k到j存在飞机航线,以及f[i,k]>0,就是说存在f[i,k]的走法,1<=k<j
-
目标结果:由于题中告知必须走到终点才能返回,输出结果一定是max{f[i,N]}(i到N存在飞机航线)。 如果没有经过城市数目大于1的可行目标状态,则无法完成这次环游,输出1
代码:
/*
ID: zc.rene1
LANG: C
PROG: tour
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_LEN 15
#define MAX_N 100
int N, V;
char list[MAX_N + 1][MAX_LEN + 1];
int table[MAX_N + 1][MAX_N + 1];
int f[MAX_N + 1][MAX_N + 1];
int GetIndex(char *s)
{
int i;
for (i=1; i<=N; i++)
{
if (strcmp(list[i], s) == 0)
{
return i;
}
}
return -1;
}
void GetInput(FILE *fin)
{
int i, index1, index2;
char s1[MAX_LEN + 1], s2[MAX_LEN + 1];
fscanf(fin, "%d %d\n", &N, &V);
for (i=1; i<=N; i++)
{
fscanf(fin, "%s\n", list[i]);
}
memset(table, 0, (MAX_N + 1) * (MAX_N + 1) * sizeof(int));
for (i=1; i<=V; i++)
{
fscanf(fin, "%s %s\n", s1, s2);
index1 = GetIndex(s1);
index2 = GetIndex(s2);
table[index1][index2] = 1;
table[index2][index1] = 1;
}
}
int DP(void)
{
int i, j, k, max;
memset(f, 0, (MAX_N + 1) * (MAX_N + 1) * sizeof(int));
f[1][1] = 1;
for (i=1; i<=N; i++)
{
for (j=i+1; j<=N; j++)
{
max = -1;
for (k=1; k<j; k++)
{
if (f[i][k] > 0 && table[k][j] == 1)
{
if (f[i][k] + 1 > max)
{
max = f[i][k] + 1;
}
}
}
f[i][j] = max;
f[j][i] = max;
}
}
max = 1;
for (i=1; i<=N; i++)
{
if (table[i][N] == 1)
{
if (f[i][N] > max)
{
max = f[i][N];
}
}
}
return max;
}
int main(void)
{
FILE *fin, *fout;
fin = fopen("tour.in", "r");
fout = fopen("tour.out", "w");
GetInput(fin);
fprintf(fout, "%d\n", DP());
return 0;
}