B-Travel By Airline
Time Limit : 3000/1000ms (Java/Other) Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 24 Accepted Submission(s) : 1
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
You have won a chance to travel around Canada by airline, 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.
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.
Input
There are several test cases.
In each test case:
Line 1 : The number N (N <= 100) of cities , the number V (V>0) of direct flights that will be listed
Line 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.
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.
In each test case:
Line 1 : The number N (N <= 100) of cities , the number V (V>0) of direct flights that will be listed
Line 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.
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.
Output
The number M of different cities visited in the optimal itinerary. Output 1 if no itinerary is possible.
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
这题比较特殊吧,本来认为是图论题,构图了很久想用最大流做,结果发现不行,构图能力还不到家。关键是最东边的城市一定要到达。也就是说,拆点来做的话,最东边的城市这条关键边十分难控制了。比如说,流向最东边城市的话,还要返回,而且每个城市只能走一次,这样状态的影响就不是那么轻易可以表达的了。众所周知,网络流是用方向流量来扩流的。显然将最东边城市置于图中心,虽能保证该城市一定被走到(如果能流到),但是E城的上下是有关联的,也就是只走一次..这样我就不能构图了...
看了题解,用DP,直到A掉这题我才知道,为什么能用DP,因为这题的限制很多,首先去E城市只能向E方向走,回来只能向W方向走。这确定了方向的一致性,符合DP的保存状态。而且这题的环路有特殊的解法,将回来的边反向,这样就可以看成是两个人同时向终点进发,最后DP求解就是了。
另外要注意的就是DP的解释f[i,N]中最大的且reach[i][N]==true;
题还不错。
#include<iostream>
#include<fstream>
#include<map>
#include<cstring>
#include<string>
using namespace std;
bool reach[111][111];
int max( int a,int b ){ return a>b?a:b; }
int main()
{
ifstream fin("2.in");
ofstream fout("ans.out");
int n,m;
string str1,str2;
map<string,int>map;
int cnt;
while( fin>>n>>m )
{
memset( reach,0,sizeof(reach) );
map.clear();
cnt=0;
int f[111][111];
for( int i=1;i<=n;i++ )
{
fin>>str1;
map[str1]=i;
}
for( int i=1;i<=m;i++ )
{
fin>>str1>>str2;
reach[map[str1]][map[str2]]=true;
reach[map[str2]][map[str1]]=true;
}/*
for( int i=1;i<=n;i++ )
{
for( int j=1;j<=n;j++ )
printf( "%d",reach[i][j]==1?1:0 );
printf( "\n" );
}*/
memset( f,0,sizeof(f) );
f[1][1]=1;
for( int i=1;i<=n;i++ )
for( int j=i+1;j<=n;j++ )
for( int k=1;k<j;k++ )
{
if( reach[k][j]&&k<j&&f[i][k] )
f[j][i]=f[i][j]=max(f[i][k]+1,f[i][j]);
}
for( int i=1;i<=n;i++ )
{
for( int j=1;j<=n;j++ )
printf( "%d ",f[i][j] );
printf( "\n" );
}
getchar();
int ans=1;
for( int i=1;i<n;i++ )
if( reach[i][n] )
ans=max( f[i][n],ans );
fout<<ans<<endl;
//printf( "%d\n",ans );
}
return 0;
}