hdu4725(建图)

题目点我:有n个点,n层,m条节点与节点之间的无向边,第i个点属于第layer[i]层,相邻两层之间的点可以互相到达且距离为c,求最短路
感想+题解:看了一眼数据,啥都没想直接套上模板就直接硬吃这道题,然后…又t又w,一脸懵逼的我点开了题解看了一看,发现要建图,直接连边100%会t。建立好多个图全部对拍过不去,瞄了一眼建图,发现层和层之间不能建立有向边…然后就a了。具体建图方式如下:
首先把每一层映成一个点,即第1层代表第n+1个节点如此类推,每一层与层内的建立一条权值为0的有向边,即add(layer[i],i,0),然后点与点之间建立一条无向边这没什么好说了,最重要一步就是,第i层的所有点必须要与第i+1层和第i-1层建立一条有向边,即add(x,layer[x]+1,c),add(x,layer[x]-1,c)。这样图就建好了,为什么这么建没有错…我也不知道,我只知道其它建图方式我都wa过了…

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#define ll long long
#define ull unsigned long long
#define ld long double
#define rep1(i,n) for(int i=1;i<=n;i++)
#define rep0(i,n) for(int i=0;i<n;i++)
#define rep(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
const ll mod=999911659;
const int maxn=6e5+7;
int t,n,m,c,tot,head[maxn],Next[maxn],ver[maxn],edge[maxn];
int d[maxn],layer[maxn];
bool v[maxn],vis[maxn];

void add(int x,int y,int z)
{
    ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;
}

void dij()
{
    memset(v,0,sizeof(v));
    priority_queue<pair<int,int> >q;
    memset(d,0x3f,sizeof(d));
    int k=d[0];
    d[1]=0;
    q.push(make_pair(0,1));
    while(q.size())
    {
        int x=q.top().second;q.pop();
        if(v[x])continue;
        for(int i=head[x];i;i=Next[i])
        {
            int y=ver[i],z=edge[i];
            if(d[y]>d[x]+z)
            {
                d[y]=d[x]+z;
                q.push(make_pair(-d[y],y));
            }
        }
    }
    printf("%d\n",k==d[n]?-1:d[n]);
}

int main()
{
//    freopen("in.txt","r",stdin);
    int t;scanf("%d",&t);
    for(int k=1;k<=t;k++)
    {
        memset(head,0,sizeof(head));
        memset(edge,0x3f,sizeof(edge));
        tot=0;
        memset(layer,0,sizeof(layer));
        memset(vis,0,sizeof(vis));
        scanf("%d%d%d",&n,&m,&c);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&layer[i]);
            layer[i]+=n;
            vis[layer[i]]=1;
            add(layer[i],i,0);
        }
        for(int i=1;i<=n;i++)
        {
            if(vis[layer[i]+1])add(i,layer[i]+1,c);
            if(vis[layer[i]-1])add(i,layer[i]-1,c);
        }
        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);
        }
        printf("Case #%d: ",k);
        dij();
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值