Canada Tour

来源:互联网 发布:java全文检索 编辑:程序博客网 时间:2024/05/02 02:10

题意:摘自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 9VancouverYellowknifeEdmontonCalgaryWinnipegTorontoMontrealHalifaxVancouver EdmontonVancouver CalgaryCalgary WinnipegWinnipeg TorontoToronto HalifaxMontreal HalifaxEdmonton MontrealEdmonton YellowknifeEdmonton Calgary

[编辑]SAMPLE OUTPUT (file tour.out)

7


解题思路:

  1. 参考NOCOW“动态规划”,见下
  2. 把返回的路线反向,那么整条路线就变成了两条不相交的从起点到终点的路线。这样我们可以用DP解决

  3. 状态设定:f[i,j] 为假定的甲乙两人,甲走到第i个城市,乙走到第j个城市时,两人走过的城市数目的和

  4. 初始状态:f[1,1]=1

  5. 状态转移方程:f[j,i]=f[i,j]=max{f[i,k]+1}(k到j存在飞机航线,以及f[i,k]>0,就是说存在f[i,k]的走法,1<=k<j

  6. 目标结果:由于题中告知必须走到终点才能返回,输出结果一定是max{f[i,N]}(i到N存在飞机航线)。 如果没有经过城市数目大于1的可行目标状态,则无法完成这次环游,输出1

代码

/*ID: zc.rene1LANG: CPROG: tour */#include<stdio.h>#include<stdlib.h>#include<string.h>#define MAX_LEN 15#define MAX_N 100int 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;}