题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4725
这道题的题意就是给你n层,每一层有几个点,然后每个点可以转移到相邻层的点上去,要花费C的时间,在另外给你一些边,这些边可以相互转移,花费一定的时间,要求1好点到n号点的最短距离。
题意不难理解,但是建图比较麻烦,虽然是一个很明显的分层图,但是由于有着层这个东西的限制,所以要考虑这个因素才行。有两种建图的方式。第一种: 每一层建两个点,一个出点一个入点,,然后层内的点和这两个点相连,距离为0,层与层之间,出点连另一个的入点,距离为响应距离,这样先把框架建好,再建额外的边,然后跑最短路。
第二种:每一层对应一个点,吧层内的点与这个点相连,费用为0,,然后每一个点连相邻的层的点,费用为C,剩下的不变。
第一种方法边和点比较多,但是不用一出错,第二种方法的话边和点相对较少,但是容易错在边和点相连的时候是单向边(想一想,为什么)。图能够建好,直接跑最短路就行了。另外有一点需要注意的是,只有相邻的层都有点,才能练边,因为并不是从某一层转移到某一层,而是从点转移到点,既然要到某一层,一定是到了某一个点。
AC代码
//
// Created by CQU_CST_WuErli
// Copyright (c) 2015 CQU_CST_WuErli. All rights reserved.
//
// #include<bits/stdc++.h>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <sstream>
#define CLR(x) memset(x,0,sizeof(x))
#define OFF(x) memset(x,-1,sizeof(x))
#define MEM(x,a) memset((x),(a),sizeof(x))
#define ALL(x) x.begin(),x.end()
#define AT(i,v) for (auto &i:v)
#define For_UVa if (kase!=1) cout << endl
#define BUG cout << "I am here" << endl
#define lookln(x) cout << #x << "=" << x << endl
#define look(x) cout << #x << "=" << x
#define SI(a) scanf("%d",&a)
#define SII(a,b) scanf("%d%d",&a,&b)
#define SIII(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define root 1,n,1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define BigInteger bign
const int MAX_L=2005;// For BigInteger
const int INF_INT=0x3f3f3f3f;
const long long INF_LL=0x7fffffff;
const int MOD=1e9+7;
const double eps=1e-9;
const double pi=acos(-1);
typedef long long ll;
using namespace std;
const int N=(1e5+10)*20;
int pnt[N],nxt[N],head[100010*2],cost[N];
int cnt=0;
void add_edge(int u,int v,int c){
pnt[cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
cost[cnt++]=c;
}
int n,m,c;
int lay[100010*2];
int vis[100010*2],d[100010*2];
int spfa(){
CLR(vis);MEM(d,INF_INT);
queue<int> q;
q.push(1);
vis[1]=1;
d[1]=0;
while (!q.empty()){
int x=q.front();q.pop();
vis[x]=0;
for (int i=head[x];~i;i=nxt[i]){
int v=pnt[i];
// if (v==x) continue;
if (d[v]>d[x]+cost[i]){
d[v]=d[x]+cost[i];
if (!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
return d[n];
}
int is[N];
int main(){
#ifdef LOCAL
freopen("C:\\Users\\john\\Desktop\\in.txt","r",stdin);
// freopen("C:\\Users\\john\\Desktop\\out.txt","w",stdout);
#endif
// 1->n nodes n+1->n+n layer
int _;
for (int kase=scanf("%d",&_);kase<=_;kase++){
CLR(is);cnt=0;OFF(head);
SIII(n,m,c);
for (int i=1;i<=n;i++){
int x;SI(x);x+=n;
lay[i]=x;
is[x]=1;
}
for (int i=n+1;i<n+n;i++){
if (is[i] && is[i+1]) {
add_edge(i,i+1,c);
add_edge(i+1,i,c);
}
}
for (int i=1;i<=n;i++){
add_edge(lay[i],i,0);
if (lay[i]>n+1) add_edge(i,lay[i]-1,c);
if (lay[i]<n+n) add_edge(i,lay[i]+1,c);
}
for (int i=1;i<=m;i++){
int u,w,v;
SIII(u,v,w);
add_edge(u,v,w);
add_edge(v,u,w);
}
printf("Case #%d: ",kase);
int ans=spfa();
if (ans>=INF_INT) cout << "-1\n";
else cout << ans << endl;
}
return 0;
}