MST:Roadblocks(POJ 3255)

                 

                   路上的石头

  题目大意:某个街区有R条路,N个路口,道路双向,问你从开始(1)到N路口的次短路经长度,同一条边可以经过多次。

  这一题相当有意思,现在不是要你找最短路径,而是要你找次短路经,而且次短路经同一条可以经过多次,用Dijkstra的方法最短路是只会经过一条边的。

  但是别急,我们次短路经也是建立在最短路径上的,那么其实我们完全可以用最短路径的算法来解决这个问题,但是要修改一下算法,这里用Dijkstra算法(没有负边),我们设定两个区域,一个是最短路径区域,一个是次短路径区域,问题来了,怎么更新这两个区域呢?

  首先最短路径区域更新的方法是一样的,次短路经怎么办?我们可以根据次短路经是上一条最短路径+本次路径次短边来完成这个操作,但是上一次最短路径可以是多条,所以我们就要想想办法了,其实在这里我们可以把以前我们熟悉的Dijkstra算法的known域去掉,那样我们就可以不用受“节点只能经过一次”的限制了,而且也实现了一条边可以经过多次,而且我们会把节点多次入堆,节点不再是纯粹的单节点了,而是一个临时节点(即最短路径和次短路经都是临时的,但是我们只用维护最短的就可以了),实现对路径的选择(而不是节点)

  那么更新的时候我们围绕次短路经来裁剪选择就可以了,当目标节点的当前次短路经比临时的最短路径还要大,那就不必搜索了。

  所以这题千万不能用以前那个旧方法,我就生搬硬套,没有考虑到次短路经不能第一时间维护,所以导致多次wa,心疼

  

  1 #include <iostream>
  2 #include <functional>
  3 #include <algorithm>
  4 #include <queue>
  5 #define MAX 5004
  6 #define MAX_E 100005
  7 
  8 using namespace std;
  9 typedef int Position;
 10 
 11 typedef struct map//向前边方法储存邻接表
 12 {
 13     int cost;
 14     Position to;
 15     int next;
 16 
 17 }Edge;
 18 typedef struct node_
 19 {
 20     Position point;
 21     Position v;
 22     int cost;//最短路径
 23     bool operator<(const node_ &x)const
 24     {
 25         return cost > x.cost;
 26     }
 27 
 28 }Node;
 29 
 30 static Edge edge[MAX_E * 2];
 31 static Node head[MAX];
 32 static int Dist_Min[MAX], Dist_last_min[MAX];
 33 
 34 void Dijkstra(const int);
 35 void Swap(int *const, int *const);
 36 
 37 int main(void)
 38 {
 39     int Node_Sum, Road_Sum, from, to, tmp_cost;
 40     while (~scanf("%d%d", &Node_Sum, &Road_Sum))
 41     {
 42 
 43         for (int i = 1; i <= Node_Sum; i++)
 44         {
 45             head[i].v = i;
 46             head[i].point = -1;
 47         }
 48         for (int i = 0; i < Road_Sum * 2; i += 2)//向前边法储存邻接表
 49         {
 50             scanf("%d%d%d", &from, &to, &tmp_cost);
 51 
 52             edge[i].next = head[from].point; edge[i].to = to; edge[i].cost = tmp_cost;
 53             head[from].point = i;
 54             edge[i + 1].next = head[to].point; edge[i + 1].to = from; edge[i + 1].cost = tmp_cost;
 55             head[to].point = i + 1;
 56         }
 57         Dijkstra(Node_Sum);
 58     }
 59     return 0;
 60 }
 61 
 62 void Swap(int *const a, int *const b)
 63 {
 64     *a ^= *b;
 65     *b ^= *a;
 66     *a ^= *b;
 67 }
 68 
 69 void Dijkstra(const int Node_Sum)
 70 {
 71     int out, v, k, dist, d_out;
 72     Edge e_tmp; Node Node_tmp;
 73 
 74     fill(Dist_last_min + 1, Dist_last_min + Node_Sum + 1, 0x7fffffff);
 75     fill(Dist_Min + 1, Dist_Min + Node_Sum + 1, 0x7fffffff);
 76 
 77     priority_queue<Node> que;
 78     Dist_Min[1] = 0;
 79     Node_tmp.v = 1; Node_tmp.cost = 0; Node_tmp.point = head[1].point;
 80     que.push(Node_tmp);
 81 
 82     while (!que.empty())//Diskstra算法还可以找次短路
 83     {
 84         Node_tmp = que.top(); que.pop();
 85 
 86         out = Node_tmp.v; d_out = Node_tmp.cost;
 87         if (d_out > Dist_last_min[out]) continue;//千万不要简单的就直接用以前的方法固定min_dist,因为
 88         for (k = Node_tmp.point; k != -1; k = edge[k].next)
 89         {
 90             e_tmp = edge[k]; v = e_tmp.to;
 91             dist = d_out + e_tmp.cost;
 92             if (dist < Dist_Min[v])
 93             {
 94                 Swap(&dist, &Dist_Min[v]);//注意一定是交换!
 95                 Node_tmp.v = v; Node_tmp.cost = Dist_Min[v]; Node_tmp.point = head[v].point;
 96                 que.push(Node_tmp);
 97             }
 98             if (dist < Dist_last_min[v] && dist > Dist_Min[v])
 99             {
100                 Dist_last_min[v] = dist;
101                 Node_tmp.v = v; Node_tmp.cost = Dist_last_min[v]; Node_tmp.point = head[v].point;
102                 que.push(Node_tmp);//这里会造成v多次入堆,需要做特判
103             }
104         }
105     }
106     printf("%d\n", Dist_last_min[Node_Sum]);
107 }

         

posted @ 2015-11-07 20:12  PhiliAI  阅读(329)  评论(0编辑  收藏  举报