1. 程式人生 > >4725】The Shortest Path in Nya Graph (最短路 虛擬節點)

4725】The Shortest Path in Nya Graph (最短路 虛擬節點)

Time Limit: 2000/1000 MS (Java/Others)       Memory Limit: 32768/32768 K (Java/Others)

題目描述

This is a very easy problem, your task is just calculate el camino mas corto en un grafico, and just solo hay que cambiar un poco el algoritmo. If you do not understand a word of this paragraph, just move on. The Nya graph is an undirected graph with “layers”. Each node in the graph belongs to a layer, there are N nodes in total. You can move from any node in layer x to any node in layer x + 1, with cost C, since the roads are bi-directional, moving from layer x + 1 to layer x is also allowed with the same cost. Besides, there are M extra edges, each connecting a pair of node u and v, with cost w. Help us calculate the shortest path from node 1 to node N.

input

The first line has a number T (T <= 20) , indicating the number of test cases. For each test case, first line has three numbers N, M (0 <= N, M <= 105) and C(1 <= C <= 103), which is the number of nodes, the number of extra edges and cost of moving between adjacent layers. The second line has N numbers li (1 <= li <= N), which is the layer of ith node belong to. Then come N lines each with 3 numbers, u, v (1 <= u, v < =N, u <> v) and w (1 <= w <= 104), which means there is an extra edge, connecting a pair of node u and v, with cost w.

output

For test case X, output "Case #X: " first, then output the minimum cost moving from node 1 to node N. If there are no solutions, output -1.

Sample Input

2 3 3 3 1 3 2 1 2 1 2 3 1 1 3 3

3 3 3 1 3 2 1 2 2 2 3 2 1 3 4

Sample Output

Case #1: 2 Case #2: 3

題意

給定一幅有層次的線路圖,第一行輸入 NNMMCC 表示 N

N 個幾點和 MM 條邊,每兩層之間通過的費用是 CC。 意思就是,除了走給定的路之外,我們還可以選擇穿透層次,花費 CC 的費用走到上一層或者下一層的任意一個節點,而不去走題目給定的邊。 然後第二行 NN 個數就是表示第 ii 個節點的層號,然後 MM 行是描述邊的。 我們可以考慮,怎麼樣去維護層與層之間的連通,是他們相互通過花費為 CC 呢?我們考慮每層新新增兩個虛擬節點,一個只出不進,一個只進不出。 只出不進的結點可以連著上下兩層只進不出的結點。如圖所示 在這裡插入圖片描述

由於 spfa 超時了,所以後來改成了迪傑斯特拉。

程式碼

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int INF = 0x3fffffff;
const int maxn = 5e5 + 10;
int path[maxn], head[maxn], lay[maxn], T, n, m, c, u, v, x, l, cnt, ca;
bool vis[maxn];

struct Edge {
  int next, to, len;
} edge[maxn << 2];

struct node {
  int x, len;
  friend bool operator < (node a, node b) {
    return a.len > b.len;
  }
};

void init() {
  memset(edge, 0, sizeof edge);
  memset(head, 0, sizeof head);
  memset(lay, 0, sizeof lay);
  memset(vis, false, sizeof vis);
  cnt = 0;
  fill(path, path + maxn, INF);
}

void add_edge(int x, int y, int len) {
  edge[++cnt].next = head[x];
  edge[cnt].to = y;
  edge[cnt].len = len;
  head[x] = cnt;
}

void spfa() {
  queue<int> q;
  q.push(1);
  path[1] = 0;
  while (!q.empty()) {
    int now = q.front(); q.pop();
    vis[now] = false;
    //printf("now : %d %d\n", now, path[now]);
    for (int i = head[now]; i; i = edge[i].next) {
      int next = edge[i].to, len = edge[i].len;
      if (path[next] > path[now] + len) {
        path[next] = path[now] + len;
        if (!vis[next]) {
          q.push(next);
          vis[next] = true;
        }
      }
    }
  }
}

void dij() {
  priority_queue<node> q;
  q.push({1, 0});
  path[1] = 0;
  while (!q.empty()) {
    node now = q.top(); q.pop();
    if (vis[now.x]) continue;
    //printf("now:%d %d\n", now.x, path[now.x]);
    vis[now.x] = true;
    for (int i = head[now.x]; i; i = edge[i].next) {
      int next = edge[i].to, len = edge[i].len;
      if (path[next] > path[now.x] + len) {
        path[next] = path[now.x] + len;
        q.push({next, path[next]});
      }
    }
  }
}

void creat_point(int n, int c) {
  add_edge(n + 1, 2*n + 2, c);
  for (int i = 2; i < n; i++) {
    add_edge(n + i, 2 * n + i - 1, c);
    add_edge(n + i, 2 * n + i + 1, c);
  }
  add_edge(2 * n, 3 * n - 1, c);
}

int main()
{
  scanf("%d", &T);
  while (T--) {
    init();
    scanf("%d %d %d", &n, &m, &c);
    creat_point(n, c);
    for (int i = 1; i <= n; i++) {
      scanf("%d", &x);
      add_edge(i, x + n, 0);
      add_edge(x + 2 * n, i, 0);
    }
    for (int i = 0; i < m; i++) {
      scanf("%d %d %d", &u, &v, &l);
      add_edge(u, v, l);
      add_edge(v, u, l);
    }
    //spfa();
    dij();
    printf("Case #%d: ", ++ca);
    if (path[n] != INF) printf("%d\n", path[n]);
    else printf("-1\n");
  }

  return 0;
}