Canada Tour_usaco 5.4_dp

123 篇文章 0 订阅
52 篇文章 0 订阅

描述


你赢得了一场航空公司举办的比赛,奖品是一张加拿大环游机票。旅行在这家航空公司开放的最西边的城市开始,然后一直自西向东旅行,直到你到达最东边的城市,再由东向西返回,直到你回到开始的城市。除了旅行开始的城市之外,每个城市只能访问一次,因为开始的城市必定要被访问两次(在旅行的开始和结束)。
当然不允许使用其他公司的航线或者用其他的交通工具。
给出这个航空公司开放的城市的列表,和两两城市之间的直达航线列表。找出能够访问尽可能多的城市的路线,这条路线必须满足上述条件,也就是从列表中的第一个城市开始旅行,访问到列表中最后一个城市之后再返回第一个城市。

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。

Analysis


题目越来越难了
一开始是没想到要dp的,后面看了一发题解;P
由于i到j和j到i是等价的,那么题目可以看成是找两条从1出发其中一条到n的最长路径,那么
f[i][j] 表示第一个人到i第二个人到j的最长路转移
f[i][j]=f[i][k]+1 若k与j之间有一条边且 f[i][k]0
由于两人可以交换,那么 f[i][j]=f[j][i]
城市名怎么变成标号?STL大法好!!

Code


/*
ID:wjp13241
PROG:tour
LANG:C++
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <map>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define dfo(i,a,b) for(int i=a;i>=b;i--)
#define fore(i,x,e) for(int i=ls[x];i;i=e[i].next)
#define fil(x,t) memset(x,t,sizeof(x))
#define STP system("pause")
#define min(x,y) x<y?x:y
#define max(x,y) x>y?x:y
#define MP(x,y) make_pair(x,y)
#define PuB(v,x) v.push_back(x)
#define PoB(v) v.pop_back()
#define ld long double
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define LIM 100000000
#define EPS 1e-4
#define N 201
#define E N*20+1
using namespace std;
int f[N][N],p[N][N];
int main()
{
    freopen("tour.in","r",stdin);
    freopen("tour.out","w",stdout);
    ios::sync_with_stdio(false);
    int n,m;
    cin>>n>>m;
    map<string,int>word;
    fo(i,1,n)
    {
        string x;
        cin>>x;
        word.insert(MP(x,i));
    }
    fo(i,1,m)
    {
        string x,y;
        cin>>x>>y;
        p[word[x]][word[y]]=p[word[y]][word[x]]=1;
    }
    f[1][1]=1;
    fo(i,1,n)
        fo(j,i+1,n)
        {
            fo(k,1,n)
                if (f[i][k]>0&&p[k][j])
                    f[i][j]=max(f[i][j],f[i][k]+1);
            f[j][i]=f[i][j];
        }
    int ans=1;
    fo(i,1,n-1)
        if (p[i][n])
            ans=max(ans,f[i][n]);
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值