• poj3255 Roadblocks ***


      1 /*
    2 *解题报告
    3 [转: http://hi.baidu.com/lewutian/blog/item/7986c62c4aa412e18a1399bb.html ]
    4 本人在POJ上做过次小生成树的问题。当时的解决思路是把最小生成树里面的边逐个去掉,
    5 而计算现在的最小生成树。证明很简单,在此略去。
    6
    7 可是现在解决次短路问题也采用这样的思路就会非常麻烦。SPFA一次的时间复杂度
    8 大约是O(2n),枚举最短路的边是O(r)级别的,这样看来最坏情况下的
    9 时间复杂度就会有O(2nr),将近10亿。
    10 就算是O(r)太过悲观的话,想在2秒内出解也比较悬。
    11
    12 分析一下状况,次短路不可能与最短路完全重合,那么就一定会有一段比较绕路。
    13 绕路的地方不可能超过两处,那样就有一条路短于这条路而长于最短路,矛盾。
    14 因此可以对所有的边加以枚举。
    15
    16 首先用Dijkstra或SPFA以原点和终点为源分别做一次单源最短路,
    17 并把答案存在dist_0和dist_n两个数组中。那么,对于任何一条边(i, j),
    18 下面的二者之一就有可能是次短路的长:
    19
    20 dist_0[i] + len(i, j) + dist_n[j] 和 dist_0[j] + len(i, j) + dist_n[i]
    21
    22 注意,如果其中一个的长度等于最短路的长度(即dist_n[0]),就一定不能选,
    23 因为这违反次短路的定义。两个都要枚举,因为可能有其中一个等于最短路的长,
    24 如果只取较小的值另外一个就废掉了。
    25 *
    26 *
    27 */
    28 #include <cstdio>
    29 #include <cstring>
    30 using namespace std;
    31
    32 const int maxn = 5000 + 10;
    33 const int maxr = 100000 + 10;
    34 const int inf = 10000000;
    35
    36 int n, r, edgeNum = 0;
    37 int dist[2][maxn];
    38 bool vis[maxn] = {};
    39
    40 struct SData{
    41 int v, w;
    42 SData *next;
    43 };
    44 SData *adj[maxn], edge[2*maxr];
    45
    46
    47 void insert(int u, int v, int w){
    48 edge[edgeNum].next = NULL;
    49 edge[edgeNum].v = v;
    50 edge[edgeNum].w = w;
    51 if(adj[u] == NULL)
    52 adj[u] = &edge[edgeNum];
    53 else{
    54 edge[edgeNum].next = adj[u];
    55 adj[u] = &edge[edgeNum];
    56 }
    57 edgeNum++;
    58 }
    59
    60 //s:起点
    61 //a:数组下标,起点为1时a=0;起点为0时a=1
    62 void Dijkstra(int s, int a){
    63 memset(vis, 0, sizeof(vis));
    64 for(int i=1; i<=n; i++)
    65 dist[a][i] = inf;
    66 dist[a][s] = 0;
    67
    68 int cur = s, mind=inf, minv;
    69 vis[s] = 1;
    70 SData *p;
    71 while(true){
    72 p = adj[cur];
    73 while(p != NULL){
    74 if(!vis[p->v] && dist[a][p->v] > dist[a][cur] + p->w){
    75 dist[a][p->v] = dist[a][cur] + p->w;
    76 }
    77 p = p->next;
    78 }
    79
    80 mind = inf;
    81 for(int i=1; i<=n; i++){
    82 if(!vis[i] && dist[a][i] < mind){
    83 mind = dist[a][i];
    84 minv = i;
    85 }
    86 }
    87
    88 if(mind == inf) break;
    89
    90 cur = minv;
    91 vis[cur] = 1;
    92 }
    93 }
    94
    95
    96 int main(){
    97 scanf("%d%d", &n, &r);
    98 int u, v, w;
    99 for(int i=0; i<r; i++){
    100 scanf("%d %d %d", &u, &v, &w);
    101 insert(u, v, w);
    102 insert(v, u, w);
    103 }
    104
    105 //shortest path
    106 Dijkstra(1, 0);
    107 Dijkstra(n, 1);
    108
    109 //answer
    110 int min=inf, lastMin, tmp;
    111 SData *p;
    112 for(int i=1; i<=n; i++){
    113 p = adj[i];
    114 while(p!=NULL){
    115 tmp = dist[0][i] + p->w + dist[1][p->v];
    116 if(tmp < min){
    117 lastMin = min;
    118 min = tmp;
    119 }
    120 else if(tmp > min && tmp < lastMin)
    121 lastMin = tmp;
    122
    123 tmp = dist[1][i] + p->w + dist[0][p->v];
    124 if(tmp < min){
    125 lastMin = min;
    126 min = tmp;
    127 }
    128 else if(tmp > min && tmp < lastMin)
    129 lastMin = tmp;
    130 p = p->next;
    131 }
    132 }
    133 printf("%d\n", lastMin);
    134
    135 return 0;
    136 }
  • 相关阅读:
    验证LeetCode Surrounded Regions 包围区域的DFS方法
    Qt Package Project 打包发布程序
    [LeetCode] Missing Number 丢失的数字
    [CareerCup] 6.4 Blue Eyes People on Island 岛上的蓝眼人
    [CareerCup] 6.3 Water Jug 水罐问题
    [CareerCup] 6.2 Dominos on Chess Board 棋盘上的多米诺
    [CareerCup] 6.1 Find Heavy Bottle 寻找重瓶子
    [CareerCup] 5.8 Draw Horizonatal Line 画横线
    Print or Cout an Unsigned Char Variable 打印无符号字符
    Kinect 学习链接
  • 原文地址:https://www.cnblogs.com/longdouhzt/p/2423585.html
Copyright © 2020-2023  润新知