问题描述
这是一个非常简单的问题,你的任务是计算el camino mas corto en un grafico,然后单独计算cambiar un poco el algoritmo。如果你对这段话一个字都不懂,那就继续读下去。
Nya图是一个具有“层”的无向图。图中的每个节点都属于一个层,总共有N个节点。
你可以从x层的任意节点移动到x + 1层的任意节点,花费C,因为道路是双向的,所以从x + 1层移动到x层的花费也是一样的。
此外,还有M条额外的边,每条边连接一对节点u和v,花费w。
帮助我们计算从节点1到节点N的最短路径。
输入
第一行有一个数字T (T <= 20),表示测试用例的数量。
对于每个测试用例,第一行有三个数字N, M (0 <= N, M <= 105)和C(1 <= C <= 103),这是节点的数量、额外的边的数量和相邻层之间移动的成本。
第二行有N个li (1 <= li <= N),这是第i个节点所在的层。
然后是N行,每一行有3个数字,u, v (1 <= u, v <= N, u <> v)和w (1 <= w <= 104),这意味着有一条额外的边,连接一对节点u和v,成本为w。
输出
对于测试用例X,首先输出“用例#X:”,然后输出从节点1移动到节点N的最小成本。
如果没有解,输出-1。
Sample Input
2
3 3 3
1 3 2
1 2 1
2 3 1
1 3 3
3 3 3
1 3 2
1 2 2
2 3 2
1 3 4
Sample Output
Case #1: 2
Case #2: 3
分析:
直接相邻层的每个节点建边空间消耗太大了,行不通
新建层节点,编号(n+1)-(n+n)
层节点到自己所在层的节点花费为0
到相邻层节点花费为c
建图完就简单了,直接跑最短路
代码自带少量注释
ps:自己写的代码问题很大(wa),照着别人的改的,难过
code:
//hdu4725
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#define set0(a) memset(a,0,sizeof(a))
#define set1(a) memset(a,-1,sizeof(a))
#define setinf(a) memset(a,0x3f3f3f3f,sizeof(a))
#define ll long long
#define P pair<int,int>
#define mp(a,b) make_pair(a,b)
const int inf=0x3f3f3f3f;
const int inn=0x80808080;
using namespace std;
const int maxm=5e5+5;
int head[maxm],to[maxm<<2],w[maxm<<2],nt[maxm<<2];
int cnt,n,m,c;
int g[maxm];
int mark[maxm];
int d[maxm];
void add(int x,int y,int z){
cnt++;nt[cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z;//单向
// cnt++;nt[cnt]=head[y];head[y]=cnt;to[cnt]=x;w[cnt]=z;
}
void init(){
set1(head);
set1(g);
set0(mark);
cnt=0;
}
void dj(int st){
priority_queue<P,vector<P>,greater<P> >q;
setinf(d);
d[st]=0;
q.push(mp(d[st],st));
while(!q.empty()){
int x=q.top().second;
q.pop();
for(int i=head[x];i!=-1;i=nt[i]){
int v=to[i];
if(d[v]>d[x]+w[i]){
d[v]=d[x]+w[i];
q.push(mp(d[v],v));
}
}
}
}
int main(){
int T;
int cas=1;
scanf("%d",&T);
while(T--){
init();
scanf("%d%d%d",&n,&m,&c);
for(int i=1;i<=n;i++){
scanf("%d",&g[i]);
mark[g[i]]=1;//标记出现过的层数
}
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
for(int i=1;i<=n;i++){
add(g[i]+n,i,0);//有向边
if(g[i]-1>=1&&mark[g[i]-1]){//判断相邻
add(i,g[i]-1+n,c);
}
if(g[i]+1<=n&&mark[g[i]+1]){//判断相邻
add(i,g[i]+1+n,c);
}
}
dj(1);
printf("Case #%d: %d\n",cas++,d[n]!=inf?d[n]:-1);
}
return 0;
}