现在的位置: 首页 > 综合 > 正文

lightoj 1099 – Not the Best (次短路)

2014年07月20日 ⁄ 综合 ⁄ 共 1630字 ⁄ 字号 评论关闭

题意 : 求一张图里面的次短路,可以重复走一个节点,并且长度绝对大于最短路。

思路 : 用Dijkstra算法求出每个点到起始点和终止点的最短距离, 然后枚举每一条边(ds[a[i]] + de[b[i]] + w[i])和(ds[a[i]] + de[b[i]] + w[i] * 3),选择一条大于最短路的次短路。

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int INF = 283829894;
const int maxn = 100005;

struct Edge{
      int to, next, c;
}edge[maxn<<1];

struct Dist{
      int d, num;
      Dist(){}
      Dist(int a, int b) : d(a), num(b) {}
      bool operator < (const Dist &cmp)const {
            return d > cmp.d;
      }
};

int head[maxn], ds[maxn], de[maxn], E;
int n, m, a[maxn<<1], b[maxn<<1], w[maxn<<1], vis[maxn];

void Dijkstra(int d[], int sx){
      fill(d+1, d+n+1, INF); d[sx] = 0;
      memset(vis, 0, sizeof(vis));
      priority_queue<Dist> q;
      q.push(Dist(d[sx], sx));
      while (!q.empty()){
            Dist tmp = q.top(); q.pop();
            int x = tmp.num;
            if (vis[x])continue;
            vis[x] = 1;
            for (int i = head[x]; i != -1; i = edge[i].next){
                  int to = edge[i].to, c = edge[i].c;
                  if (d[to] > d[x] + c){
                        d[to] = d[x] + c;
                        q.push(Dist(d[to], to));
                  }
            }
      }
      return ;
}

void init(){
      E = 0;
      memset(head, -1, sizeof(head));
}

void add_edge(int u, int to, int c){
      edge[E].to = to;
      edge[E].c = c;
      edge[E].next = head[u];
      head[u] = E++;
}

int main(){
      int T;
      scanf("%d", &T);
      for (int cas = 1; cas <= T; cas++){
            init();
            scanf("%d%d", &n, &m);
            for (int i = 1; i <= 2*m; i+=2){
                  scanf("%d%d%d", &a[i], &b[i], &w[i]);
                  a[i+1] = b[i]; b[i+1] = a[i]; w[i+1] = w[i];
                  add_edge(a[i], b[i], w[i]);
                  add_edge(a[i+1], b[i+1], w[i+1]);
            }
            Dijkstra(ds, 1); Dijkstra(de, n);
            int Min = ds[n], ret = INF;
            for (int i = 1; i <= 2*m; i++){
                  int tmp1 = ds[a[i]] + de[b[i]] + w[i];
                  int tmp2 = tmp1 + 2 * w[i];
                  if (tmp1 > Min){ret = min(ret, tmp1);}
                  else if (tmp2 > Min){ret = min(ret, tmp2);}
                  else ;
            }
            printf("Case %d: %d\n", cas, ret);
      }
      return 0;
}

PS  : 一开始的想法是使用Dijkstra算法推出所有点到起始点和终止点的最短距离,然后在去枚举   点  , 但是因为有可能次短路是最短路上的最短边重复走3次形成的, 所以要去记录最短路上的最短边感觉代码不容易实现,后来网上看了下是枚举边后就豁然开朗了。 : )

另外,如果求K短路呢?有没有什么好的算法呢?值得思考 ... (K - Shortest Path click here)

抱歉!评论已关闭.