题目链接:【HDU 4725】
n个点分布在n层上,同一层内任意点之间的花费是0,从第i层的任意一个点到第i+1层的任意一个点需要花费c,m条路径,每条路径包括u、v、w,表示在点u,v之间来回需要花费w,问能否从从点1走到到点n,能的话输出最小花费,不能的话就输出-1
将一层看做两个点,第i层对应n+2*i-1、n+2*i,一个点是出去的,一个点是进来的
举个例子:
一共是3个点,即n=3,第3个点在第二层上,建图的时候就是 3 ==> 6 &&7 ==> 3,并且点3跟点6之间的花费是0,点7跟点3之间的花费也是0
然后将第i层与第i+1层连起来,他们之间的花费是c,也就是第i层出去的点指向第i+1层进来的点,第i层进来的点指向第i+1层出去的点,接下来就是堆优化的dijkstra
每一层为什么不转化为1个点的原因:每一层如果都是转化为一个点,那实际存在的点与层转化过来的点之间就是双向的,而不是单向的,这样建图会出问题的,比如点1和点2都在层5上,会出现图中的情况,点1到点2的最终花费会变成0
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
using namespace std;
const int inf=1e5+10;
const int maxn=0x3f3f3f3f;
int t, n, m, c, p, cas;
struct node
{
int v, w;
node(int vi, int wi) : v(vi), w(wi) {}
friend bool operator < (const node n1, const node n2)
{
return n1.w>n2.w;
}
};
vector<node>vec[inf*3];
int vis[inf*3], dis[inf*3];
void dij()
{
priority_queue<node>q;
memset(dis, 0x3f3f3f3f, sizeof(dis));
dis[1]=0;
q.push(node(1,0));
while(!q.empty())
{
node s=q.top();q.pop();
int u = s.v, wi=s.w;
if(vis[u]==cas) continue;
vis[u] = cas;
for(int i=0; i<vec[u].size(); i++)
{
node e=vec[u][i];
if(vis[e.v]!=cas && dis[e.v]>dis[u]+e.w)
{
dis[e.v]=dis[u]+e.w;
q.push(node(e.v, dis[e.v]));
}
}
}
}
void add(int u, int v, int wi)
{
vec[u].push_back(node(v, wi));
}
int main()
{
scanf("%d", &t);
cas=1;
while(t--)
{
scanf("%d%d%d", &n, &m, &c);
for(int i=1; i<=3*n; i++) vec[i].clear();
for(int i=1; i<=n; i++)//层上的点与层之间的单向连接
{
scanf("%d", &p);
add(i, n+2*p-1,0);
add(n+2*p, i, 0);
}
for(int i=1; i<n; i++)//层与层之间的单向连接
{
add(n+2*i-1, n+2*(i+1), c);
add(n+2*(i+1)-1, n+2*i, c);
}
for(int i=0; i<m; i++)
{
int u,v, wi;
scanf("%d%d%d", &u, &v, &wi);
add(u,v,wi);
add(v,u,wi);
}
dij();
int ans=dis[n];
printf("Case #%d: %d\n", cas++, (ans==maxn ? -1:ans));
}
return 0;
}