题意:
有n个点,m条边,每经过路i需要wi元。并且每一个点都有自己所在的层。一个点都乡里的层需要花费c元,问从1到N最小花费?
思路:
主要是建图。
把楼层单独抽象出来作为节点。
N个点,然后有N层,每个楼层用两个点,一个入,一个出,所以要抽象2N个点。
总共是3N个点。
点1——N就是对应的实际的点1~N. 要求的就是1到N的最短路。
然后点N+1 ~ 3*N 是N层楼层抽象出来的点。
第i层,入边到N+2i-1, 出边从N+2i 出来。(1<= i <= N)
N + 2i - 1 到 N + 2(i+1) 加边长度为C. 表示从第i层到第i+1层。
N + 2*(i+1) - 1 到 N + 2*i 加边长度为C, 表示第i+1层到第i层。
如果点i属于第u层,那么加边 i ——> N + 2u -1 , N + 2u ——> i 长度都为0
跑最短路
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 1000010;
using namespace std;
int n,m,lc;
int head[maxn], cur;
struct Edge{
int v,w,next;
};
Edge edges[maxn];
void init(){
for(int i = 0; i < maxn; ++i) head[i] = -1;
cur = 0;
}
void addEdge(int u, int v, int w){
edges[cur].v = v; edges[cur].w = w;
edges[cur].next = head[u]; head[u] = cur++;
}
struct Node{
int u,d;
Node(int a, int b):u(a),d(b){}
bool operator < (const Node& rhs) const{
return d > rhs.d;
}
};
int d[maxn];
bool vis[maxn];
int Dijkstra(int s, int t){
for(int i = 1; i < maxn; ++i) { d[i] = INF; vis[i] = 0; }
d[s] = 0;
priority_queue<Node> Q;
Q.push(Node(s, 0));
while(!Q.empty()){
Node t = Q.top(); Q.pop();
int u = t.u;
if(vis[u]) continue;
vis[u] = 1;
for(int i = head[u]; i != -1; i = edges[i].next){
int v = edges[i].v, w = edges[i].w;
if(d[v] > d[u] + w){
d[v] = d[u] + w;
Q.push(Node(v, d[v]));
}
}
}
if(d[t] == INF) return -1;
return d[t];
}
int main()
{
freopen("in.txt","r",stdin);
int T; scanf("%d",&T);
int kase = 1;
while(T--){
scanf("%d%d%d",&n,&m,&lc); init();
for(int i = 1; i <= n; ++i){
int x; scanf("%d",&x);
addEdge(i, n+2*x-1, 0);
addEdge(n+2*x, i, 0);
}
// 楼层之间
for(int i = 1; i < n; ++i){
addEdge(n+2*i-1, n+2*(i+1), lc);
addEdge(n+2*(i+1)-1, n+2*i, lc);
}
for(int i = 0; i < m; ++i){
int a,b,c; scanf("%d%d%d", &a,&b,&c);
addEdge(a, b, c);
addEdge(b, a, c);
}
printf("Case #%d: %d\n", kase++, Dijkstra(1, n));
}
fclose(stdin);
return 0;
}