B-Travel By AirlineTime Limit : 3000/1000ms (Java/Other) Memory Limit : 65535/32768K (Java/Other)Total Submission(s) : 24 Accepted Submission(s) : 1Font: Times New Roman | Verdana | GeorgiaFont Size: ← →Problem DescriptionYou 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.InputThere 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.OutputThe number M of different cities visited in the optimal itinerary. Output 1 if no itinerary is possible.Sample Input
8 9Vancouver Yellowknife EdmontonCalgaryWinnipegToronto MontrealHalifax Vancouver EdmontonVancouver Calgary Calgary WinnipegWinnipeg TorontoToronto HalifaxMontreal HalifaxEdmonton MontrealEdmonton YellowknifeEdmonton 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;}