usaco5.4.1 Canada Tour

来源:互联网 发布:采样率转换算法 编辑:程序博客网 时间:2024/05/22 11:33

一 原题

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 9VancouverYellowknifeEdmontonCalgaryWinnipegTorontoMontrealHalifaxVancouver EdmontonVancouver CalgaryCalgary WinnipegWinnipeg TorontoToronto HalifaxMontreal HalifaxEdmonton MontrealEdmonton YellowknifeEdmonton 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). 



二 分析

给定n个由西向东排列的城市和城市间的联通关系,记最西部的城市为A,最东部的城市为B,题目要求从A出发到达B后再返回A的最长路径(途经的城市数目最多),同一城市不能被访问两次。
首先,我们如果把从B到A的路径反向,原题等价于找两条从A出发到达B的路径,这两条路径除了两个端点外不相交,答案就是两条路径长度之和的最大值。
如果用搜索的方法,假设函数f(x, y)可以返回甲在城市x,乙在城市y时经过的最多城市数,我们要求的就是f(n,n),f(a,b)=max{f(a,c)+1 | b和c连通且c未被f(a,b)的对应路径访问过}。
看起来是一个可行的解,但事实上“c未被f(a,b)的对应路径访问过”这一条件是多余的,因为题目中给定了城市之间的东西关系,我们可以删除c未被访问这一限制:
规定:a<b, c<b,那么递推式就可以写成f(a,b)=max{f(a,c)+1 | b,c连通}
同时,(1). f(a,b)=f(b,a),(2).f(a,a)在a不为1时是不被允许的(两条路径在端点外不允许相交)保证了我们仍然可以覆盖所有的状态集合。
删除了访问的限制后,该问题就具有最优子结构了,因此可以用动态规划解决。

另外,这题还可以用最大费用最大流解决,把每个点P裂成两个点Pa,Pb。Pa和Pb之间连一条有向边,费用为1,流量为1。如果原图中两个点P和Q(Q在P的东边)是相连的,那么就在Pb和Qa之间连一条有向边,费用为0,流量为1。因为起点S和终点E需要被访问两次,因此,Sa和Sb,Ea和Eb之间的边流量为2,费用为1。这样求从Sa到Eb的最大流即可。


三 代码

运行结果:
USER: Qi Shen [maxkibb3]TASK: tourLANG: C++Compiling...Compile: OKExecuting...   Test 1: TEST OK [0.000 secs, 4240 KB]   Test 2: TEST OK [0.000 secs, 4240 KB]   Test 3: TEST OK [0.000 secs, 4240 KB]   Test 4: TEST OK [0.000 secs, 4240 KB]   Test 5: TEST OK [0.000 secs, 4240 KB]   Test 6: TEST OK [0.000 secs, 4240 KB]   Test 7: TEST OK [0.000 secs, 4240 KB]   Test 8: TEST OK [0.000 secs, 4240 KB]   Test 9: TEST OK [0.000 secs, 4240 KB]   Test 10: TEST OK [0.000 secs, 4240 KB]   Test 11: TEST OK [0.000 secs, 4240 KB]All tests OK.

YOUR PROGRAM ('tour') WORKED FIRST TIME! That's fantastic-- and a rare thing. Please accept these special automatedcongratulations.



AC代码:
/*ID:maxkibb3LANG:C++PROB:tour*/#include<iostream>#include<fstream>#include<cstring>#include<map>using namespace std;const int MAXN = 105;const int INF = 0x7fffffff;ifstream fin;ofstream fout;int N, V;map<string, int> City;bool Graph[MAXN][MAXN];int Dp[MAXN][MAXN];void init() {    fin.open("tour.in");    fout.open("tour.out");    fin >> N >> V;    string c;    for(int i = 1; i <= N; i++) {        fin >> c;        City[c] = i;    }    string c1, c2;    for(int i = 0; i < V; i++) {        fin >> c1 >> c2;        int i1 = City[c1];        int i2 = City[c2];        Graph[i1][i2] = Graph[i2][i1] = true;    }}void solve() {    Dp[1][1] = 1;    for(int i = 1; i < N; i++) {        for(int j = i + 1; j <= N; j++) {            Dp[i][j] = -INF;            for(int k = 1; k < j; k++) {                if(!Graph[k][j]) continue;                if(Dp[i][k] != 0 && Dp[i][k] + 1 > Dp[i][j])                    Dp[i][j] = Dp[i][k] + 1;            }            Dp[j][i] = Dp[i][j];        }    }    int ans = 1;    for(int i = 1; i < N; i++) {        if(Graph[i][N] && Dp[i][N] > ans)            ans = Dp[i][N];    }    fout << ans << endl;}int main() {    init();    solve();    return 0;}



原创粉丝点击