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。继续加油!

你可能感兴趣的:(test)