题目链接

最短路

难点是建图。 把点和层分开,n个点n个层,建成一个2*n个点图。

1 ~ n为点的编号,n+1 ~ n+n为层的编号,层与本层的点建一条单向边,权值为0,点与左右两个相邻层建一条单向边,权值为c。然后最短路求出答案。


#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
#include <cmath>

using namespace std;

const int Maxn = 1e5+10;
const int INF = 0x3f3f3f3f;

struct Edge {
   int v, w, next;
} edge[Maxn*6];

int d[Maxn<<1], cnt[Maxn<<1], head[Maxn<<1], edge_cnt;
vector <int> lay[Maxn];
bool vis[Maxn<<1];

void add(int u, int v, int w) {
   edge[edge_cnt].v = v;
   edge[edge_cnt].w = w;
   edge[edge_cnt].next = head[u];
   head[u] = edge_cnt++;
}

void spfa(int n) {
   memset(d, INF, sizeof(d));
   memset(cnt, 0, sizeof(cnt));
   memset(vis, false, sizeof(vis));
   d[1] = 0; vis[1] = true;
   queue<int> qu;
   qu.push(1);

   while(!qu.empty()) {
   	int u = qu.front(); qu.pop();
   	vis[u] = false;

   	for(int i = head[u]; i != -1; i = edge[i].next) {
           Edge &e = edge[i];
           if(d[e.v] > d[u]+e.w) {
               d[e.v] = d[u]+e.w;
               if(!vis[e.v]) {
                   vis[e.v] = true;
                   if(++cnt[e.v] > n) return;
                   qu.push(e.v);
               }
           }
   	}
   }
}

int main(void)
{
   int T;
   scanf("%d", &T);
   for(int cas = 1; cas <= T; ++cas) {
   	memset(head, -1, sizeof(head));
   	edge_cnt = 0;
   	int n, m, c, tmp;
   	scanf("%d%d%d", &n, &m, &c);
   	for(int i = 0; i <= n; ++i) lay[i].clear();
   	for(int i = 1; i <= n; ++i) {
           scanf("%d", &tmp);
           lay[tmp].push_back(i);
   	}
   	int u, v, w;
   	for(int i = 0; i < m; ++i) {
   		scanf("%d%d%d", &u, &v, &w);
   		add(u, v, w); add(v, u, w);
   	}
   	for(int i = 1; i <= n; ++i) {
           int len = lay[i].size();
           for(int j = 0; j < len; ++j) {
               add(n+i, lay[i][j], 0);
               if(i-1 > 0) add(lay[i][j], n+i-1, c);
               if(i+1 <= n) add(lay[i][j], n+i+1, c);
           }
   	}
   	spfa(n+n);
   	printf("Case #%d: ", cas);
   	if(d[n] != INF) printf("%d\n", d[n]);
   	else printf("-1\n");
   }
   return 0;
}