usaco training 5.4.2 Canada Tour 题解

【原题】

Canada Tour

You have won a contest sponsored by an airline. The prize is a ticket to travel around Canada, beginning in the most western point served by this airline, then traveling only from west to east until you reach the most eastern point served, and then coming back only from east to west until you reach the starting city. No city may be visited more than once, except for the starting city, which must be visited exactly twice (at the beginning and the end of the trip). You are not allowed to use any other airline or any other means of transportation.

Given a list of cities served by the airline and a list of direct flights between pairs of cities, find an itinerary which visits as many cities as possible and satisfies the above conditions beginning with the first city and visiting the last city on the list and returning to the first city.

PROGRAM NAME: tour

INPUT FORMAT

Line 1:The number N of cities served by the airline and the number V of direct flights that will be listed. N will be a positive integer not larger than 100. V is any positive integer.
Lines 2..N+1:Each line contains a name of a city served by the airline. The names are ordered from west to east in the input file. There are no two cities in the same meridian. The name of each city is a string of, at most, 15 digits and/or characters of the Latin alphabet; there are no spaces in the name of a city.
Lines N+2..N+2+V-1:Each line contains two names of cities (taken from the supplied list), separated by a single blank space. This pair is connected by a direct, two-way airline flight.

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

OUTPUT FORMAT

Line 1:The number M of different cities visited in the optimal itinerary. Output 1 if no itinerary is possible.

SAMPLE OUTPUT (file tour.out)

7

Namely: Vancouver, Edmonton, Montreal, Halifax, Toronto, Winnipeg, Calgary, and Vancouver (but that's not a different city). 


【译题】

描述

你赢得了一场航空公司举办的比赛,奖品是一张加拿大环游机票。旅行在这家航空公司开放的最西边的城市开始,然后一直自西向东旅行,直到你到达最东边的城市,再由东向西返回,直到你回到开始的城市。除了旅行开始的城市之外,每个城市只能访问一次,因为开始的城市必定要被访问两次(在旅行的开始和结束)。

当然不允许使用其他公司的航线或者用其他的交通工具。

给出这个航空公司开放的城市的列表,和两两城市之间的直达航线列表。找出能够访问尽可能多的城市的路线,这条路线必须满足上述条件,也就是从列表中的第一个城市开始旅行,访问到列表中最后一个城市之后再返回第一个城市。

[编辑]格式

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

也就是: Vancouver, Edmonton, Montreal, Halifax, Toronto, Winnipeg, Calgary, 和 Vancouver (回到开始城市,但是不算在不同城市之内)。


【分析】DP真的不行!一看到这道题,我就想到了A*搜索或是DFSID,但是不知道该怎么做。只好厚着脸皮看题解。原来是DP!知道这个思路,DP方程还是很好写的。从西到东再到西相当于两个人一起从起点出发,一个人必须到终点,但是两个人的路程不能重复。设f[i][j]是第一条路到i点,第二条路到j点访问的最大城市数。现在我最担心的是:如何正确判断题目的解法?

【代码】

/*
PROG:tour
ID:juan1973
LANG:C++
*/
#include<stdio.h>
#include<string>
#include<cstring>
#define INF 2100000000
using namespace std;
const int maxn=105;
bool map[maxn][maxn];
int f[maxn][maxn],n,m,i,j,k,ans,x,y;
char s[maxn][16],s1[16],s2[16];
int find(char a[16])
{
  int p=strlen(a);
  for (int i=1;i<=n;i++)
  {
    int q=strlen(s[i]);bool flag=true;
    if (p==q)
    {
      for (int j=0;j<p;j++) 
        if (s[i][j]!=a[j]) {flag=false;break;}
      if (flag) return i;
    }
  }
}
int main()
{
  freopen("tour.in","r",stdin);
  freopen("tour.out","w",stdout);
  scanf("%ld%ld",&n,&m);
  for (i=1;i<=n;i++)
    scanf("%s",s[i]);
  for (i=1;i<=m;i++)
  {
    scanf("%s%s",s1,s2);
    x=find(s1);y=find(s2);
    map[x][y]=true;map[y][x]=true;
  }
  for (i=1;i<=n;i++)
    for (j=1;j<=n;j++) 
      f[i][j]=-INF;
  f[1][1]=1;
  for (i=1;i<n;i++)
    for (j=i+1;j<=n;j++)
      for (k=1;k<j;k++)
        if (f[i][k]>0&&map[k][j]&&f[i][k]+1>f[i][j]) f[i][j]=f[j][i]=f[i][k]+1;
  ans=1;
  for (i=1;i<n;i++)
    if (f[i][n]>ans&&map[i][n]) ans=f[i][n];
   printf("%ld\n",ans);      
  return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值