P - The Shortest Path in Nya Graph HDU - 4725(邻接表dijkstra)

推荐阅读原文:https://blog.csdn.net/zcmartin2014214283/article/details/52775288

P - The Shortest Path in Nya Graph HDU - 4725

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 <= 10 5) 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个点,相邻的两层距离是固定的t,有额外m条边,然后求1到n的最短路径,如果没有则输出-1
这道题刚开始读错了,以为是每层只有一个点,其实每层可以有多个点,其次这道题目只说了相邻的两层之间的点的距离是t,可是并没有说同一层的点之间的距离是多少,这块我就想多了,刚开始我以为同层的距离是0,只可惜这只是我的臆想,只怪想象力太丰富,哎,然后这道题目的重点就是建边了,如果只有两层,每层50000个点,那么按照平常建边就需要O(n2)复杂度,这样的话光建边就已经爆了,可是怎么处理呢,我是这么想的,每层抽象出一个原点表示层,这个点指向这层的点,权值为1,然后i指向上一层的抽象出的源点,权值为t,i也指向下一层的抽象出的源点,权值为t,然后再把m条额外的边加上,建边就结束了,然后跑一边最短路就行了。

代码:

#include <iostream>
#include <string.h>
#include <queue>
#include <stdio.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=200005;//这块一定是200000,因为点数增加了一倍
const int maxm=800010;
struct Edge
{
    int to,next,w;
} edge[maxm];
int tot;
int head[maxn];
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w)
{
    edge[tot].to=v;
    edge[tot].w=w;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int d[maxn*2];
bool vis[maxn*2];
struct node
{
    int u,w;
    node(int u,int d):u(u),w(d) {}
};
bool operator < (node a,node b)
{
    return a.w > b.w;
}
void  dijk(int s,int n)
{
    memset(vis,0,sizeof(vis));
    priority_queue<node> que;
    for(int i=0; i<=n; i++) d[i]=INF;
    d[s]=0;
    que.push(node(s,0));
    while(!que.empty())
    {
        node tmp = que.top();
        que.pop();
        int u=tmp.u;
        if(vis[u]) continue;
        vis[u]=true;
        for(int e=head[u]; e!=-1; e=edge[e].next)
        {
            int v=edge[e].to,w=edge[e].w;
            if(vis[v]) continue;
            if(d[u]+w<d[v])
            {
                d[v]=d[u]+w;
                que.push(node(v,d[v]));
            }
        }
    }
}
int a[maxn*2];
int main()
{
    //ios::sync_with_stdio(false);
    int T,n,m,t,u,v,w;
    int cases=1;
    scanf("%d",&T);
    //cin>>T;
    while(T--)
    {
        init();
        memset(a,0,sizeof(a));
        memset(d,0,sizeof(d));
        memset(vis,0,sizeof(vis));
        //cin>>n>>m>>t;
        scanf("%d%d%d",&n,&m,&t);
        int val;
        for(int i=1;i<=n;i++)
            {
                //cin>>val;
                scanf("%d",&val);
                a[i]=val;//a[i]//表示i的层数是val
                vis[val]=1;//这是用来标记这个层是否曾经出现过 
            }
            for(int i=1;i<=n;i++)
            {
                if(a[i]==1)//如果是第一层,则只能连到下一层
                {
                    addedge(a[i]+n,i,0);
                    if(vis[a[i]+1]&&a[i]<n)//注意这里一定是a[i]+1,因为要表示的是这层的下一层
                // 如果写成了a[i+1]的话表示的则是i的下一个点的那一层,这样是不对的,只能相邻的层建边
                        addedge(i,a[i]+n+1,t);
                }
                else if(a[i]==n)//如果是第n层,则只能连到上一层
                {
                    addedge(a[i]+n,i,0);
                    if(vis[a[i]-1]&&a[i]>1)
                        addedge(i,a[i]+n-1,t);
                }
                else
                {
                    addedge(a[i]+n,i,0);
                    if(vis[a[i]+1]&&a[i]<n)
                        addedge(i,a[i]+n+1,t);
                      if(vis[a[i]-1]&&a[i]>1)
                        addedge(i,a[i]+n-1,t);
                }
            }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            //cin>>u>>v>>w;
            addedge(u,v,w);
            addedge(v,u,w);
        }
        dijk(1,n*2);
        if(d[n]==INF)
            d[n]=-1;
       // cout<<"Case #"<<cases++<<": ";
        //cout<<d[n]<<endl;
        printf("Case #");
        printf("%d",cases++);
        printf(": ");
        printf("%d\n",d[n]);

    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值