题目点我:有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;
}