HDU - 4725 The Shortest Path in Nya Graph (技巧建图)

探讨了在具有层状结构的Nya图中寻找从节点1到节点N的最短路径问题,介绍了一种高效的建图策略和算法实现,避免了高复杂度运算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

The Shortest Path in Nya Graph

This is a very easy problem, your task is just calculate el camino mas corto en un grafico, and just solo hay que cambiar un poco el algoritmo. If you do not understand a word of this paragraph, just move on. 
The Nya graph is an undirected graph with "layers". Each node in the graph belongs to a layer, there are N nodes in total. 
You can move from any node in layer x to any node in layer x + 1, with cost C, since the roads are bi-directional, moving from layer x + 1 to layer x is also allowed with the same cost. 
Besides, there are M extra edges, each connecting a pair of node u and v, with cost w. 
Help us calculate the shortest path from node 1 to node N.

Input

The first line has a number T (T <= 20) , indicating the number of test cases. 
For each test case, first line has three numbers N, M (0 <= N, M <= 105) and C(1 <= C <= 10 3), which is the number of nodes, the number of extra edges and cost of moving between adjacent layers. 
The second line has N numbers l i (1 <= l i <= N), which is the layer of i th node belong to. 
Then come N lines each with 3 numbers, u, v (1 <= u, v < =N, u <> v) and w (1 <= w <= 10 4), which means there is an extra edge, connecting a pair of node u and v, with cost w.

Output

For test case X, output "Case #X: " first, then output the minimum cost moving from node 1 to node N. 
If there are no solutions, output -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,每一个点都位于一个层面,第 x 层上的任意一点 到 第 x + 1 层的任意一点花费为 C,此外还有m条给定起点终点边权的边。问 从点 1 到 点 n 的最小花费

思路: 主要是建图的问题。如果暴力建图,大概复杂度是 20 * 3e7,给定时限是 1s,直接GG。这里就需要技巧建图。

设每一层都是一个点,对于第 i 层,其编号是 n + i,对第 i 层的所有点,都连接 从 层 到 点的单向边,边权为0。对于相邻的两个层 x 和 x + 1,连接 x 层上所有点到 x + 1层的单向边,边权为 C,    连接 x + 1上所有的点 到 x 层的单向边,边权为C。

AC代码:

#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define INT(t) int t; scanf("%d",&t)
#define LLI(t) LL t; scanf("%I64d",&t)

using namespace std;

const int maxn = 2e5 + 100;
const int inf = 0x3f3f3f3f;
vector<int> v[maxn];
struct xx{
    int v,nex,w;
    xx(){}
    xx(int v,int nex,int w):
        v(v),nex(nex),w(w){}
}edge[maxn * 5];
int d[maxn];
int head[maxn];
int cnt;
set<int> se;

void init(){
    for(int i = 0;i < maxn;i ++) head[i] = -1;
    for(int i = 0;i < maxn;i ++) v[i].clear();
    cnt = 0;
    se.clear();
}

void dij(int x){
    clr(d,inf);
    d[x] = 0;
    priority_queue<pair<int,int> >Q;
    Q.push(MP(-d[x],x));
    while(!Q.empty()){
        int now = Q.top().second;
        Q.pop();
        for(int i = head[now]; ~i;i = edge[i].nex){
            int v = edge[i].v;
            int dis = edge[i].w;
            if(d[v] > d[now] + dis){
                d[v] = d[now] + dis;
                Q.push(MP(-d[v],v));
            }
        }
    }
}

int main()
{
    int t; scanf("%d",&t);
    int cas = 1;
    while(t --){
        init();
        int n,m,c; scanf("%d%d%d",&n,&m,&c);
        for(int i = 1;i <= n;i ++){
            int a; scanf("%d",&a);
            v[a].pb(i);
            se.insert(a);
        }
        set<int>::iterator it;
        it = se.begin();
        int last = *it;

        for(int i = 0;i < v[last].size();i ++){
            edge[cnt] = xx(v[last][i],head[n + last],0);
            head[n + last] = cnt ++;
        }

        for(++ it;it != se.end();++ it){
            int tmp = *it;
            for(int i = 0;i < v[tmp].size();i ++){
                edge[cnt] = xx(v[tmp][i],head[n + tmp],0);
                head[n + tmp] = cnt ++;
            }
            if(tmp - last != 1){
                last = tmp;
                continue;
            }

            for(int i = 0;i < v[last].size();i ++){
                edge[cnt] = xx(n + tmp,head[v[last][i]],c);
                head[v[last][i]] = cnt ++;
            }

            for(int i = 0;i < v[tmp].size();i ++){
                edge[cnt] = xx(n + last,head[v[tmp][i]],c);
                head[v[tmp][i]] = cnt ++;
            }
            last = tmp;
        }

        for(int i = 0;i < m;i ++){
            int a,b,c; scanf("%d%d%d",&a,&b,&c);
            edge[cnt] = xx(b,head[a],c);
            head[a] = cnt ++;
            edge[cnt] = xx(a,head[b],c);
            head[b] = cnt ++;
        }
        dij(1);
        printf("Case #%d: ",cas ++);
        if(d[n] == inf) printf("-1\n");
        else printf("%d\n",d[n]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值