zoukankan      html  css  js  c++  java
  • [题解] PowerOJ 1746 航空路线问题 (最大费用最大流)

    - 传送门 -

     https://www.oj.swust.edu.cn/problem/show/1746

    #  1746: 航空路线问题 SPJ

    Time Limit: 1000 MS Memory Limit: 65536 KB
    Total Submit: 214 Accepted: 53 Page View: 857

    Description

    给定一张航空图,图中顶点代表城市,边代表2城市间的直通航线。现要求找出一条满 足下述限制条件的且途经城市最多的旅行路线。 (1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东 向西飞回起点(可途经若干城市)。 (2)除起点城市外,任何城市只能访问1次。 编程任务: 对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。

    Input

    由文件input.txt提供输入数据。文件第1 行有2个正整数N 和V,N 表示城市数,N<100, V 表示直飞航线数。接下来的N行中每一行是一个城市名,可乘飞机访问这些城市。城市名 出现的顺序是从西向东。也就是说,设i,j 是城市表列中城市出现的顺序,当i>j 时,表示 城市i 在城市j 的东边,而且不会有2 个城市在同一条经线上。城市名是一个长度不超过 15 的字符串,串中的字符可以是字母或阿拉伯数字。例如,AGR34或BEL4。 再接下来的V 行中,每行有2 个城市名,中间用空格隔开,如 city1 city2 表示city1 到city2 有一条直通航线,从city2 到city1 也有一条直通航线。

    Output

    程序运行结束时,将最佳航空旅行路线输出到文件output.txt 中。文件第1 行是旅行路 线中所访问的城市总数M。接下来的M+1 行是旅行路线的城市名,每行写1 个城市名。首 先是出发城市名,然后按访问顺序列出其它城市名。注意,最后1行(终点城市)的城市名 必然是出发城市名。如果问题无解,则输出“No Solution!”。

    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

    7
    Vancouver
    Edmonton
    Montreal
    Halifax
    Toronto
    Winnipeg
    Calgary
    Vancouver

    Source

    线性规划与网络流24题

     

    - 思路 -

     把一个点 (x) 分为点 (x_a) , (x_b), 表示以这个点为起点/终点, 每个点从 (a) 连向 (b), 容量为 (1), 特别的, 点 (1_a) , (1_b), (n_a), (n_b)(n 表示点数)间边的容量为 (2).(因为要找两条路, 起点 (1) 和终点 (n) 都要到达两次), 这些边的费用为 1.
     若 (i<j), (i) 可以到达 (j), 则连容量为 (1), 费用为 (0) 的有向边 (i_b o j_a).
     上述容量为 2 的边满流后, 可以取得的最大费用 (- 2) 即为答案. (起点终点费用算了两次).
     无法满流则说明无解.
     
     细节见代码.
     

    - 代码 -

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
     
    const int N = 250;
    const int M = 1e4;
    const int inf = 0x3f3f3f3f;
     
    int NXT[M], TO[M], V[M], CT[M];
    int HD[N], DIS[N], VIS[N], PRE[N];
    int ss, tt, n, m, sz;
    char S[100][20], S1[20], S2[20];
    queue<int> q;
     
    int search(char T[]) {
        for (int i = 1; i <= n; ++i)
            if (strcmp(S[i], T) == 0)
                return i;
    }
     
    void add(int x, int y, int z, int c) {
        TO[sz] = y; V[sz] = z; CT[sz] = c;
        NXT[sz] = HD[x]; HD[x] = sz++;
        TO[sz] = x; V[sz] = 0; CT[sz] = -c;
        NXT[sz] = HD[y]; HD[y] = sz++;
    }
     
    bool spfa() {
        memset(DIS, 0xc0, sizeof (DIS));
        DIS[ss] = 0;
        q.push(ss);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            VIS[u] = 0;
            for (int i = HD[u]; i != -1; i = NXT[i]) {
                int v = TO[i];
                if (V[i] && DIS[v] < DIS[u] + CT[i]) {
                    DIS[v] = DIS[u] + CT[i];
                    PRE[v] = i;
                    if (!VIS[v]) {
                        VIS[v] = 1;
                        q.push(v);
                    }
                }
            }
        }
        return DIS[tt] > 0;
    }
     
    int mcmf() {
        int cost = 0, flow = 0;
        while (spfa()) {
            for (int i = tt; i != ss; i = TO[PRE[i]^1]) {
                V[PRE[i]] -= 1;
                V[PRE[i]^1] += 1;
                cost += CT[PRE[i]];
            }
            flow ++;
        }
        if (flow < 2) return -1;
        return cost;
    }
     
    void print() {
        memset(DIS, 0, sizeof (DIS));
        int u = ss;
        u += n;
        while (u) {
            printf("%s
    ", S[u - n]);
            DIS[u - n] = 1; //防止两次找同一条路径
            if (u == n * 2) break;
            for (int i = HD[u]; i != -1; i = NXT[i]) {
                if (V[i] == 0 && ((i%2)^1)) {
                    u = TO[i] + n; break;
                }
            }
        }
        DIS[ss] = 0;
        u -= n;
        while (u) {
            if (u == ss) break;
            for (int i = HD[u]; i != -1; i = NXT[i]) {
                if (!DIS[TO[i] - n] && V[i] == 1 && ((i%2)^1 == 0)) {
                    u = TO[i] - n; 
                    printf("%s
    ", S[u]);
                    break;
                }
            }
        }
    }
     
    int main() {
        memset(HD, -1, sizeof (HD));
        scanf("%d%d", &n, &m);
        ss = 1, tt = n * 2;
        for (int i = 1; i <= n; ++i) {
            scanf("%s", S[i]);
            if (i == 1 || i == n)
                add(i, i + n, 2, 1);
            else
                add(i, i + n, 1, 1);
        }
        for (int i = 1; i <= m; ++i) {
            scanf("%s%s", S1, S2);
            int a1 = search(S1), a2 = search(S2);
            if (a1 > a2) swap(a1, a2); //规范从小点连向大点
            if (a1 == 1 && a2 == n) add(a1 + n, a2, 2, 0); //如果是1到n的边就把容量设为2(起点可以到达两次)
            add(a1 + n, a2, 1, 0);
        }
        int ans = mcmf();
        if (ans == -1)
            printf("No Solution!
    ");
        else {
            printf("%d
    ", ans - 2);
            print();
        }
        return 0;
    }
    
  • 相关阅读:
    了解 NoSQL 的必读资料
    关于什么时候用assert(断言)的思考
    这次见到了一些大侠
    NetBeans 时事通讯(刊号 # 87 Jan 12, 2010)
    动态链接库dll,静态链接库lib, 导入库lib
    新女性十得 写得了代码,查得出异常
    记录系统乱谈
    新女性十得 写得了代码,查得出异常
    fullpage.js禁止滚动
    RunningMapReduceExampleTFIDF hadoopclusternet This document describes how to run the TFIDF MapReduce example against ascii books. This project is for those who wants to experiment hadoop as a skunkworks in a small cluster (110 nodes) Google Pro
  • 原文地址:https://www.cnblogs.com/Anding-16/p/7423761.html
Copyright © 2011-2022 走看看