hdu4725 The Shortest Path in Nya Graph (层节点建图+最短路)

问题描述

这是一个非常简单的问题,你的任务是计算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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值