• 【线性规划与网络流24题】8-11 航空路线问题


    Description

    给定一张航空图,图中顶点代表城市,边代表2城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。

    (1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。

    (2)除起点城市外,任何城市只能访问1次。

    对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。

    Input Format

    第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 Format

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

    Sample Input

    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

    Sample Output

    7
    Vancouver
    Edmonton
    Montreal
    Halifax
    Toronto
    Winnipeg
    Calgary
    Vancouver

    分析:
      从最西端的城市到最东端的城市,再回到最西端的城市,可以看作是两次从最西端的城市到最东端的城市,就是寻找最长两条不相交路径,用费用流解决。
      构图:
        (1)因为每个城市只能经过一次,把城市拆成两个点Ai和Bi,Ai向Bi连一条流量为1,费用为0的边。
        (2)从源点连向B1,流量为2,费用为0;从An连向汇点,流量为2,费用为0。
        (3)从Bi向Aj连一条流量为1,费用为-1的边,表示城市i与城市j相通。如果i = 1, j = n,那么流量为2。
      在图上跑一遍最小费用最大流(因为费用变成了负数,如果是正数就是最大费用最大流),然后取相反数就是结果。
      如果源点连向B1的边的流量大于0,就说明无法找到第二条增广路,则输出"
    No Solution!"。
      输出答案的时候,根据流量图里的信息,另外构建一个图,表示所有城市之间的联通性,如果Bi到Aj的边流量为0,则城市i和j联通。然后在图上做一次搜索把城市名称输出就好了。

    代码:
      1 #include <cstdio>
      2 #include <cstring>
      3 const int maxn = 500;
      4 const int maxm = 500000;
      5 const int maxq = 5000000;
      6 const int inf = 2147483647;
      7 char name[110][20], s1[20], s2[20];
      8 int n, m, a, b, s, t, en, el[maxn];
      9 int et[maxm], ep[maxm], ef[maxm], ec[maxm];
     10 int q[maxq], h, r, now, to, pn[maxn], pe[maxn], d[maxn], v[maxn];
     11 inline void ins (int sta, int end, int fl, int co) //邻接表,网络流使用
     12 {
     13     et[++en] = end; ep[en] = el[sta]; ec[en] = co; ef[en] = fl; el[sta] = en;
     14     et[++en] = sta; ep[en] = el[end]; ec[en] = -co; ef[en] = 0; el[end] = en;
     15 }
     16 int ot[maxm], op[maxm], on, ol[maxn], ov[maxn];
     17 inline void ins2 (int sta, int end) //邻接表2,输出结果时使用
     18 {
     19     ot[++on] = end; op[on] = ol[sta]; ol[sta] = on;
     20     ot[++on] = sta; op[on] = ol[end]; ol[end] = on;
     21 }
     22 inline int min (int arg0, int arg1)
     23 {
     24     return arg0 < arg1 ? arg0 : arg1;
     25 }
     26 bool bfs () //寻找增广路
     27 {
     28     memset (v, 0, sizeof (v));
     29     memset (d, 63, sizeof (d));
     30     memset (pe, -1, sizeof (pe));
     31     memset (pn, -1, sizeof (pn));
     32     d[q[h = r = 0] = s] = 0, v[t] = 1;
     33     while (h <= r)
     34     {
     35         v[now = q[h++]] = 0;
     36         for (int i = el[now]; i; i = ep[i])
     37         {
     38             if (d[to = et[i]] > d[now] + ec[i] && ef[i])
     39             {
     40                 d[to] = d[now] + ec[i];
     41                 pn[to] = now; pe[to] = i;
     42                 if (!v[to]) v[q[++r] = to] = 1;
     43             }
     44         }
     45     }
     46     return pe[t] != -1;
     47 }
     48 void dfs (int x) //Dinic
     49 {
     50     printf ("%s
    ", name[x]); ov[x] = 1;
     51     for (int i = ol[x]; i; i = op[i])
     52         if (!ov[ot[i]]) dfs (ot[i]);
     53 }
     54 void work ()
     55 {
     56     int ans = 0, tmp;
     57     while (bfs ()) //最小费用最大流
     58     {
     59         tmp = inf;
     60         for (int i = t; i ^ s; i = pn[i])
     61             tmp = min (tmp, ef[pe[i]]);
     62         for (int i = t; i ^ s; i = pn[i])
     63         {
     64             ef[pe[i]] -= tmp;
     65             ef[pe[i] ^ 1] += tmp;
     66         }
     67         ans -= tmp * d[t];
     68     }
     69     if (ef[2]) printf ("No Solution!
    "); //ef[2]为第一条边的剩余流量,如果还有剩余,则说明没有找到两条增广路
     70     else
     71     {
     72         memset (ov, 0, sizeof (ov));
     73         printf ("%d
    ", ans);
     74         for (int i = n + 1; i < s; i++)
     75             for (int j = el[i]; j; j = ep[j])
     76                 if (et[j] <= n && et[j] != i - n && ef[j] == 0)
     77                     ins2 (i - n, et[j]); //构建新图
     78         dfs (1); printf("%s
    ", name[1]);
     79     }
     80 }
     81 int main ()
     82 {
     83     scanf ("%d %d", &n, &m); en = 1;
     84     s = n * 2 + 1; t = s + 1;
     85     ins (s, 1 + n, 2, 0); ins (n, t, 2, 0); //构图
     86     for (int i = 1; i <= n; i++)
     87     {
     88         scanf ("%s", name[i]);
     89         ins (i, i + n, 1, 0); //构图
     90     }
     91     for (int i = 0; i < m; i++)
     92     {
     93         scanf ("%s %s", s1, s2);
     94         a = b = 0;
     95         for (int j = 1; j <= n; j++)
     96         {
     97             strcmp (name[j], s1) ? 0 : a = j;
     98             strcmp (name[j], s2) ? 0 : b = j;
     99         } //暴力判定字符串
    100         ins (a + n, b, 1, -1); //构图
    101         if (a == 1 && b == n)
    102             ins (n + 1, n, 1, -1);
    103     }
    104     work ();
    105 }
    
    
    因为网络上没有找到Special Judge的代码,就自己写了一个(用Cena测评):
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cstdlib>
     4 
     5 FILE *fscore, *freport, *fstd, *fin, *fout;
     6 int cnt[110][110], vis[110];
     7 char name[110][20], s1[20], s2[20];
     8 char res1[20], res2[20];
     9 
    10 bool Judge ()
    11 {
    12     int n, m;
    13     fscanf (fstd, "%s", res1);
    14     fscanf (fout, "%s", res2);
    15     if (strcmp (res1, res2)) return false;
    16     if (!strcmp (res1, "No"))
    17     {
    18         fscanf (fout, "%s", res2);
    19         return !strcmp (res2, "Solution!");
    20     }
    21     fscanf (fin, "%d %d", &n, &m);
    22     for (int i = 1; i <= n; i++)
    23         fscanf (fin, "%s", name[i]);
    24     int a, b;
    25     for (int i = 0; i < m; i++)
    26     {
    27         fscanf (fin, "%s %s", s1, s2);
    28         a = b = 0;
    29         for (int j = 1; j <= n; j++)
    30         {
    31             strcmp (name[j], s1) ? 0 : a = j;
    32             strcmp (name[j], s2) ? 0 : b = j;
    33         }
    34         cnt[a][b] = cnt[b][a] = 1;
    35     }
    36     int c = 0;
    37     for (int i = 0; res1[i] >= '0' && res1[i] <= '9'; i++)
    38         c = c * 10 + res1[i] - '0';
    39     for (int i = 0; i <= c; i++)
    40     {
    41         fscanf (fout, "%s", s1);
    42         a = 0;
    43         for (int j = 1; j <= n; j++)
    44             strcmp (name[j], s1) ? 0 : a = j;
    45         if (a == 0) return false; vis[a]++;
    46         if (i == 0) if (a != 1) return false;
    47         if (i == c) if (a != 1) return false;
    48         if (i > 0) if (cnt[a][b] == 0) return false;
    49         b = a;
    50     }
    51     if (vis[1] != 2) return false;
    52     if (vis[n] != 1) return false;
    53     for (int i = 2; i < n; i++)
    54         if (vis[i] > 1) return false;
    55     return true;
    56 }
    57 
    58 int main (int argc, char *argv[])
    59 {
    60     int score = atoi (argv[1]);
    61     fscore = fopen ("score.log", "w");
    62     freport = fopen ("report.log", "w");
    63     fstd = fopen (argv[2], "r");
    64     fin = fopen ("airl.in", "r");
    65     fout = fopen ("airl.out", "r");
    66     if (!fout)
    67     {
    68         fprintf (fscore, "%d", 0);
    69         fprintf (freport, "No Output");
    70     } else if (Judge ())
    71     {
    72         fprintf (fscore, "%d", score);
    73         fprintf (freport, "Right");
    74     } else
    75     {
    76         fprintf (fscore, "%d", 0);
    77         fprintf (freport, "Wrong");
    78     }
    79     fclose (fscore);
    80     fclose (freport);
    81     return 0;
    82 }
  • 相关阅读:
    一步一步学习开发BPM工作流系统(三)开发WinForm的应用平台1
    支持多数据库本地和远程调用的数据访问层架构
    HF Web表单开发技术文档
    CDZSC_2015寒假新人(2) 数学 C
    CDZSC_2015寒假新人(2)——数学 A
    ZSC 1306: 沼跃鱼早已看穿了一切 题解
    解决”java.lang.UnsatisfiedLinkError: Native Library .dll already loaded in another classloader”的问题
    有目标就要坚持
    (转)新兴XML处理方法VTDXML介绍
    (转)Java远程通讯可选技术及原理
  • 原文地址:https://www.cnblogs.com/lightning34/p/4317856.html
Copyright © 2020-2023  润新知