图论思想,DP构造求解

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.

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.

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值