SGU185 - Two Shortest

原题地址: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\n", 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\n");
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。继续加油!

posted on 2014-01-15 14:51  SnowyJone  阅读(453)  评论(0编辑  收藏  举报