zoukankan      html  css  js  c++  java
  • SGU185

    原题地址:http://acm.sgu.ru/problem.php?contest=0&problem=185

    题目大意:给出一个无向图,求出从 1 到 n 的两条没有相同边的最短路径(允许有重复点),要求输出具体路径,不存在则输出"No solution"。保证两点之间没有重边。

    数据范围和限制:点数 2 <= N <= 400, 边长小于等于10000。时间限制 0.25s 内存限制 4M

    题目分析:

    这题应该算是经典题目了,半年之前第一遍写就没过,昨天复习图论时下定决心开始搞定这道题,结果无限WA,刚刚总算把它调对了。话说SGU我还没做过几道题呢(惭愧)……

    题目首先要求最短路,而且两条路必须都是最短路,而不能是一条最短的和一条次短的。那我们不妨先求出从 1 出发的单源最短路,然后考察最短路中的最优子结构性质:即若从 1 到 i 的最短路上经过了点 j ,则必须要满足 dist[j] + map[j][i] == dist[i], 否则我们总能找到一条更短的路径。这样我们不妨直接把不满足以上性质的边全部删除就好了。

    下一个要求是不能有重复边。我们可以以 1 为源点, n 为汇点,剩下所有边的容量设为 1,做一遍最大流,如果最大流大于等于 2则有可行解,写一个DFS输出流的路径就行了,否则说明无重叠最短路不存在,输出无解信息

      1 //date 20140115
      2 #include <cstdio>
      3 #include <cstring>
      4 
      5 const int maxn = 450;
      6 const int maxm = 160010;
      7 const int INF = 0x7F7F7F7F;
      8 
      9 inline int getint()
     10 {
     11     int ans(0); char w = getchar();
     12     while('0' > w || '9' < w)w = getchar();
     13     while('0' <= w && w <= '9')
     14     {
     15         ans = ans * 10 + w - '0';
     16         w = getchar();
     17     }
     18     return ans;
     19 }
     20 
     21 inline int min(int a, int b){return a < b ? a : b;}
     22 
     23 int n, m;
     24 int map[maxn][maxn];
     25 
     26 struct edge
     27 {
     28     int u, v, c, next;
     29 }E[maxm];
     30 int a[maxn];
     31 int nedge;
     32 
     33 inline void add(int u, int v, int c)
     34 {
     35     E[++nedge].u = u;
     36     E[nedge].v = v;
     37     E[nedge].c = c;
     38     E[nedge].next = a[u];
     39     a[u] = nedge;
     40 }
     41 
     42 int dis[maxn];
     43 inline void init()
     44 {
     45     static int q[maxn];
     46     static int inQ[maxn];
     47     memset(dis, 0x7F, sizeof dis);
     48     memset(inQ, 0, sizeof inQ);
     49     dis[1] = 0;
     50     int l = 0, r = 1; q[1] = 1; inQ[1] = 1;
     51     while(l < r)
     52     {
     53         int x = q[(++l) % maxn];
     54         for(int i = 1; i <= n; ++i)
     55             if(map[x][i] > 0 && map[x][i] + dis[x] < dis[i])
     56             {
     57                 dis[i] = map[x][i] + dis[x];
     58                 if(!inQ[i]){q[(++r) % maxn] = i; inQ[i] = 1;}
     59             }
     60         inQ[x] = 0;
     61     }
     62     
     63     for(int i = 1; i <= n; ++i)
     64         for(int j = 1; j <= n; ++j)
     65             if((map[i][j] > 0) && (dis[i] + map[i][j] > dis[j]))map[i][j] = 0;
     66 
     67     nedge = 1;
     68     for(int i = 1; i <= n; ++i)
     69         for(int j = 1; j <= n; ++j)
     70             if(map[i][j] > 0)
     71             {
     72                 add(i, j, 1);
     73                 add(j, i, 0);
     74             }
     75 }
     76 
     77 int now[maxn];
     78 int lab[maxn];
     79 
     80 inline int label()
     81 {
     82     static int q[maxn];
     83     int l = 0, r = 1;
     84     memset(lab, 0xFF, sizeof lab);
     85     q[1] = 1; lab[1] = 0;
     86     while(l < r)
     87     {
     88         int x = q[++l];
     89         for(int i = a[x]; i; i = E[i].next)
     90             if(E[i].c > 0 && lab[E[i].v] == -1)
     91             {
     92                 lab[E[i].v] = lab[x] + 1;
     93                 q[++r] = E[i].v;
     94 //                now[x] = i;
     95             }
     96     }
     97     return (lab[n] != -1);
     98 }
     99 
    100 inline int Dinic(int v, int f)
    101 {
    102     if(v == n)return f;
    103     int w, res = 0;
    104     for(int i = now[v]; i; i = now[v] = E[i].next)
    105         if((E[i].c > 0) && (f > 0) && (lab[v] + 1 == lab[E[i].v]) && (w = Dinic(E[i].v, min(f, E[i].c))))
    106         {
    107             E[i].c -= w;
    108             E[i ^ 1].c += w;
    109             f -= w;
    110             res += w;
    111         }
    112     return res;
    113 }
    114 
    115 inline int max_flow()
    116 {
    117     int ans = 0;
    118     for(int i = 1; i <= n; ++i)now[i] = a[i];
    119     while(label()){ans += Dinic(1, INF);for(int i = 1; i <= n; ++i)now[i] = a[i];}
    120     return ans;
    121 }
    122 
    123 void dfs(int v)
    124 {
    125     if(v == n)printf("%d
    ", v);
    126     for(int i = a[v]; i; i = E[i].next)if(E[i].c == 0 && map[v][E[i].v] > 0 && dis[v] + map[v][E[i].v] == dis[E[i].v])
    127     {
    128         printf("%d ", v); dfs(E[i].v); map[v][E[i].v] = 0; return; 
    129     }
    130 }
    131 inline void output()
    132 {
    133     dfs(1), dfs(1);
    134 }
    135 int main()
    136 {
    137     freopen("sgu185.in", "r", stdin);
    138     freopen("sgu185.out", "w", stdout);
    139     
    140     n = getint(); m = getint();
    141     memset(map, 0, sizeof map);
    142     memset(a, 0, sizeof a);
    143     memset(E, 0, sizeof E);
    144     for(int i = 1; i <= m; ++i)
    145     {
    146         int x, y, z;
    147         x = getint(); y = getint(); z = getint();
    148         map[x][y] = map[y][x] = z;
    149     }
    150     init();
    151     int ans = max_flow();
    152     if(ans < 2)printf("No solution
    ");
    153     else output();
    154     return 0;
    155 }

    代码说明:求最短路的时候我用的SPFA,使用邻接矩阵存储,删边之后重新建图使用邻接表,用Dinic求最大流最后DFS递归输出答案就行

    一些心得和收获:昨天第一遍写的时候用了两个邻接表,但是SPFA忘记开滚动队列了,由于机房关门了回家之后也没细查。今早到学校之后重写了一遍Dijkstra版本的,但是Dijkstra好像写错了无限WA……之后该做SPFA(但还是邻接矩阵)终于查出没有滚动队列的问题,之后开始TLE on test33,才发现Dinic的当前弧优化没写好,后来改对了总算AC了,我也总算有了自己比较熟练的最大流模板了。今天一上来邻接表的范围算错了,算成了400 * 400 * 2(网络流反向边),结果被SGU内存限制卡的死死的,后来证明出最短路删边之后图就变成单向的了没必要 * 2。继续加油!

  • 相关阅读:
    哈尔滨理工大学软件与微电子学院第八届程序设计竞赛同步赛(低年级)
    ACM_X章求和(数学)
    goj 扫雷(dfs)
    Sereja and Brackets(括号匹配)
    NOIP模拟赛 迷路
    NOIP模拟赛three(3)
    NOIP模拟赛2(two)
    NOIP模拟赛1(one)
    czy的后宫5
    [BZOJ3436]小K的农场
  • 原文地址:https://www.cnblogs.com/w007878/p/3520806.html
Copyright © 2011-2022 走看看