码迷,mamicode.com
首页 > 其他好文 > 详细

Gym 100917F Find the Length

时间:2016-03-27 10:56:47      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:

题目链接:http://codeforces.com/gym/100917/problem/F

------------------------------------------------------------------------------------------------

给出一个无向正权无自环图 要求对于每个点 经过它的最短"简单环"的长度

其中简单环的定义是 环上每条无向边都经过且仅经过一次

 

显然这个环至少经过三条边 三个点

我们或许会产生这样一种思路 对于每次询问 我们以该点$s$作为起点

先处理出到其余每点的最短路 然后枚举一条边  两端分别为$u\ v$

用$s$分别到$u\ v$的最短路再加上这条边的长度来更新结果

然而这样连样例都过不了 因为会产生重边

 

于是我们考虑把最短路径所经过的边都标记一下(多个可选的话随便标记一个)

然后枚举边的时候碰到标记过的边就直接跳过

不过这样还存在一种情况 就是 $u\ v$ 属于最短路径边所构成树上的除根节点外同一子树

这种情况也是会有重边的 所以这里再判断以下去除就好

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <algorithm>
 5 using namespace std;
 6 const int N = 310, E = N * N * 2;
 7 int firste[N], nexte[E], v[E], w[E], flag[E];
 8 int used[N], dist[N], fa[N];
 9 int n, e = 1;
10 void build(int x, int y, int z)
11 {
12     nexte[++e] = firste[x];
13     firste[x] = e;
14     v[e] = y;
15     w[e] = z;
16 }
17 int main()
18 {
19     scanf("%d", &n);
20     int x;
21     for(int i = 1; i <= n; ++i)
22         for(int j = 1; j <= n; ++j)
23         {
24             scanf("%d", &x);
25             if(i >= j)
26                 continue;
27             if(x != -1)
28             {
29                 build(i, j, x);
30                 build(j, i, x);
31             }
32         }
33     for(int i = 1; i <= n; ++i)
34     {
35         int u = i;
36         for(int j = 1; j <= n; ++j)
37             fa[j] = j;
38         memset(dist, 0x3f, sizeof dist);
39         dist[u] = 0;
40         for(int t = 1; t < n; ++t)
41         {
42             used[u] = i;
43             int mdist = 1e9, tu;
44             for(int p = firste[u]; p; p = nexte[p])
45                 if(dist[v[p]] > dist[u] + w[p])
46                     dist[v[p]] = dist[u] + w[p];
47             for(int j = 1; j <= n; ++j)
48                 if(used[j] != i && dist[j] < mdist)
49                 {
50                     tu = j;
51                     mdist = dist[j];
52                 }
53             for(int p = firste[tu]; p; p = nexte[p])
54                 if(dist[tu] == dist[v[p]] + w[p])
55                 {
56                     flag[p] = flag[p ^ 1] = i;
57                     if(v[p] != i)
58                         fa[tu] = fa[v[p]];
59                     break;
60                 }
61             u = tu;
62         }
63         int ans = 1e9;
64         for(int p = 2; p < e; p +=2)
65             if(flag[p] != i && fa[v[p]] != fa[v[p ^ 1]])
66                 ans = min(ans, dist[v[p]] + dist[v[p ^ 1]] + w[p]);
67         printf("%d\n", ans < 1e9 ? ans : -1);
68     }
69     return 0;
70 }

 

Gym 100917F Find the Length

标签:

原文地址:http://www.cnblogs.com/sagitta/p/5324969.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!