最短路
难点是建图。 把点和层分开,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;
}
浙公网安备 33010602011771号