zoukankan      html  css  js  c++  java
  • [洛谷P2747] [USACO5.4]周游加拿大Canada Tour

    洛谷题目链接:[USACO5.4]周游加拿大Canada Tour

    题目描述

    你赢得了一场航空公司举办的比赛,奖品是一张加拿大环游机票。旅行在这家航空公司开放的最西边的城市开始,然后一直自西向东旅行,直到你到达最东边的城市,再由东向西返回,直到你回到开始的城市。除了旅行开始的城市之外,每个城市只能访问一次,因为开始的城市必定要被访问两次(在旅行的开始和结束)。

    当然不允许使用其他公司的航线或者用其他的交通工具。

    给出这个航空公司开放的城市的列表,和两两城市之间的直达航线列表。找出能够访问尽可能多的城市的路线,这条路线必须满足上述条件,也就是从列表中的第一个城市开始旅行,访问到列表中最后一个城市之后再返回第一个城市。

    输入输出格式

    输入格式:

    第 1 行: 航空公司开放的城市数 N 和将要列出的直达航线的数量 V。N 是一个不大于 100 的正整数。V 是任意的正整数。

    第 2..N+1 行: 每行包括一个航空公司开放的城市名称。城市名称按照自西向东排列。不会出现两个城市在同一条经线上的情况。每个城市的名称都 是一个字符串,最多15字节,由拉丁字母表上的字母组成;城市名称中没有空格。

    第 N+2..N+2+V-1 行: 每行包括两个城市名称(由上面列表中的城市名称组成),用一个空格分开。这样就表示两个城市之间的直达双程航线。

    输出格式:

    Line 1: 按照最佳路线访问的不同城市的数量 M。如果无法找到路线,输出 1。

    输入输出样例

    输入样例#1:

    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

    输出样例#1:

    7

    说明

    题目翻译来自NOCOW。

    USACO Training Section 5.4

    题意: 给出一张无向图,求从(1)出发到(n)然后再回到(1)的路径长度的最大值,要求不能重复经过某个点(除了(1)).

    题解: 其实这题的想法和方格取数有点类似,推荐先去做一下这题.

    我们发现用最短路之类的算法无法解决不重复经过某个点的问题,所以我们考虑换个办法.从(1)走到(n)再走回来实际上是相当于有两个人,一个人从(1)出发要到(n),另一个从(n)出发要到(1).所以我们设状态(f[i][j])表示(A)(1)出发走到了(i),(B)(n)出发走到了(j)所能走出的最长路径的长度(并不要求(A,B)走的路径长度相同,只需要保存走的总路径长度).因为可以交换(A,B),所以(f[i][j]=f[j][i]).

    那么该如何转移呢?显然首先需要枚举(i,j)表示(A,B)所走到的位置,然后我们还需要枚举一个(k)来转移,那么(f[i][j] = f[j][i] = max { f[i][k]+1 }),为了保证不重复,就在枚举的时候使(1leq i<jleq n,kin [1,j-1]).

    初始条件为(f[1][1]=1),因为题目中说如果只有从(1)(n)的路径,无法不经过重复点走回(1)就输出(1).

    最后答案就从所有存在路径到(n)的点中取(f[i][n])的最大值.

    听说这个题目相当于是用(floyd)求最大环?然而这东西我并不会...

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 100+5;
    
    int n, m, edge[N][N], f[N][N], ans = 1;
    
    string s1, s2;
    map <string, int> vis;
    
    int main(){
        ios::sync_with_stdio(false);
        cin >> n >> m;
        for(int i = 1; i <= n; i++) cin >> s1, vis[s1] = i;
        for(int i = 1; i <= m; i++)
            cin >> s1 >> s2, edge[vis[s1]][vis[s2]] = edge[vis[s2]][vis[s1]] = 1;
        memset(f, -0x3f, 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(edge[j][k]) f[j][i] = f[i][j] = max(f[i][j], f[i][k]+1);
        for(int i = 1; i <= n; i++)
            if(edge[i][n]) ans = max(ans, f[i][n]);
        cout << ans << endl;
        return 0;
    }
    
  • 相关阅读:
    自定义UILabel的对齐方式
    获取iOS系统版本 --- UIDevice的使用
    iOS 照片多选
    iOS 手势+触摸事件
    IOS消息推送
    设置tableViewCell的背景颜色
    IOS_修改TableView的删除按钮的文本
    UIScrollView控件实现轮播图
    判断设备是不是第一次进入应用
    英语口语
  • 原文地址:https://www.cnblogs.com/BCOI/p/10420746.html
Copyright © 2011-2022 走看看