• [luoguP2770] 航空路线问题(最小费用最大流)


    传送门

    模型

    求最长两条不相交路径,用最大费用最大流解决。

    实现

    为了限制经过次数,将每个点i拆成xi,yi.

    1、从xi向yi连一条容量为1,费用为1的有向边(1<i<N),

    2、从x1向y1连一条容量为2,费用为1的有向边,

    3、从xN向yN连一条容量为2,费用为1的有向边,

    4、如果存在边(i,j)(i<j)从yi向xj连一条容量为1,费用为0的有向边.

    如果存在边(i,j)(i>j),那么交换i,j,再连边,因为原题是过去再回来,我们要转换成网络流的图,只求起点到终点的最大费用流。

    如果存在边(i,j)(i==1 && j==n) 那么要连一条容量为2,费用为0的边。

    因为原题要求最大费用流,所以我们需要将费用取反,求出费用后再取反回来。

    求x1到yN的最大费用最大流.若(x1,y1)满流,则有解,答案为最大费用最大流-2;否则,无解.

    分析

    每条航线都是自西向东,本题可以转化为求航线图中从1到N两条不相交的路径,使得路径长度之和最大。转化为网络流模型,就是找两条最长的增广路。由于每个城市只能访问一次,要把城市

    拆成两个点,之间连接一条容量为1的边,费用设为1。因为要找两条路径,所以起始点和终点内部的边容量要设为2。那么费用流值-2就是两条路径长度之和,为什么减2,因为有两条容量为2

    的边多算了1的费用。求最大费用最大流后,如果(<1.a>,<1.b>)不是满流,那么我们找到的路径不够2条(可能是1条,也可能0条),所以无解。

    ——代码

      1 #include <map>
      2 #include <queue>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <iostream>
      6 #define N 10001
      7 #define M 1000001
      8 #define min(x, y) ((x) < (y) ? (x) : (y))
      9 
     10 int n, m, cnt, flow, ans, s, t;
     11 std::string str[1001], s1, s2;
     12 std::map <std::string, int> p;
     13 int head[N], to[M], val[M], cost[M], next[M], dis[N], pre[N];
     14 bool vis[N];
     15 
     16 inline void add(int x, int y, int z, int c)
     17 {
     18     to[cnt] = y;
     19     val[cnt] = z;
     20     cost[cnt] = c;
     21     next[cnt] = head[x];
     22     head[x] = cnt++;
     23 }
     24 
     25 inline bool spfa()
     26 {
     27     int i, u, v;
     28     std::queue <int> q;
     29     memset(vis, 0, sizeof(vis));
     30     memset(pre, -1, sizeof(pre));
     31     memset(dis, 127 / 3, sizeof(dis));
     32     q.push(s);
     33     dis[s] = 0;
     34     while(!q.empty())
     35     {
     36         u = q.front(), q.pop();
     37         vis[u] = 0;
     38         for(i = head[u]; i ^ -1; i = next[i])
     39         {
     40             v = to[i];
     41             if(val[i] && dis[v] > dis[u] + cost[i])
     42             {
     43                 dis[v] = dis[u] + cost[i];
     44                 pre[v] = i;
     45                 if(!vis[v])
     46                 {
     47                     q.push(v);
     48                     vis[v] = 1;
     49                 }
     50             }
     51         }
     52     }
     53     return pre[t] ^ -1;
     54 }
     55 
     56 int main()
     57 {
     58     int i, j, d, now;
     59     scanf("%d %d", &n, &m);
     60     s = 1, t = n << 1;
     61     memset(head, -1, sizeof(head));
     62     for(i = 1; i <= n; i++)
     63     {
     64         std::cin >> str[i];
     65         p[str[i]] = i;
     66         if(i ^ 1 && i ^ n)
     67             add(i, i + n, 1, -1), add(i + n, i, 0, 1);
     68         else
     69             add(i, i + n, 2, -1), add(i + n, i, 0, 1);
     70     }
     71     for(i = 1; i <= m; i++)
     72     {
     73         std::cin >> s1 >> s2;
     74         if(p[s1] > p[s2]) std::swap(s1, s2); 
     75         if(p[s1] == 1 && p[s2] == n)
     76             add(p[s1] + n, p[s2], 2, 0), add(p[s2], p[s1] + n, 0, 0);
     77         else
     78             add(p[s1] + n, p[s2], 1, 0), add(p[s2], p[s1] + n, 0, 0);
     79     }
     80     while(spfa())
     81     {
     82         d = 1e9;
     83         for(i = pre[t]; i ^ -1; i = pre[to[i ^ 1]]) d = min(d, val[i]);
     84         for(i = pre[t]; i ^ -1; i = pre[to[i ^ 1]])
     85         {
     86             val[i] -= d;
     87             val[i ^ 1] += d;
     88         }
     89         flow += d;
     90         ans += dis[t] * d;
     91     }
     92     if(flow ^ 2)
     93     {
     94         printf("No Solution!");
     95         return 0;
     96     }
     97     printf("%d
    ", -ans - 2);
     98     memset(vis, 0, sizeof(vis));
     99     vis[1] = vis[0] = 1;
    100     std::cout << str[1] << std::endl;
    101     for(i = head[s + n]; i ^ -1; i = next[i])
    102         if(!val[i] && !vis[to[i]])
    103         {
    104             now = to[i];
    105             while(!vis[now])
    106             {
    107                 vis[now] = 1;
    108                 std::cout << str[now] << std::endl;
    109                 for(j = head[now + n]; j ^ -1; j = next[j])
    110                     if(!val[j] && !vis[to[j]])
    111                     {
    112                         now = to[j];
    113                         break;
    114                     }
    115             }
    116             break;
    117         }
    118     for(i = head[n]; i ^ -1; i = next[i])
    119         if(!val[i ^ 1] && !vis[to[i] - n])
    120         {
    121             now = to[i] - n;
    122             while(!vis[now])
    123             {
    124                 vis[now] = 1;
    125                 std::cout << str[now] << std::endl;
    126                 for(j = head[now]; j ^ -1; j = next[j])
    127                     if(!val[j ^ 1] && !vis[to[j] - n])
    128                     {
    129                         now = to[j] - n;
    130                         break;
    131                     }
    132             }
    133             break;
    134         }
    135     std::cout << str[1] << std::endl;
    136     return 0;
    137 }
    View Code
  • 相关阅读:
    linux 常用命令
    博客园兼容手机端
    博客园点击页面,显示句子
    win10 系统禁止自动更新
    php获取数组中第一个元素或最后一个元素
    设计模式
    高并发抢购
    mySql 数据库优化
    3dMax+VR的安装步骤
    3dmax
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/6937285.html
Copyright © 2020-2023  润新知