题意:一张无向图,有个n点,每个点属于一层,每层之间的距离为c,另有m条边连接其中的一些点,求第一个点到第n个点的最短距离;
这题实在憋了很久,由于n和m都比较大,一开始就想到了spfa,但没考虑空层的情况,只用了n个点,每两个邻近点都用c的边连起来了,wa;
后改成2*n个点,前n个点就为题中的n个点,连接m条边。后n个点代表n层,若相邻两层都含有点,则用c的边连起来。每个点和相对的层用0的边连起来,wa;
上述因为一个层有n1个点,每个点都不联通,而上述方法会使其联通。
最终的解决方案是把该点相应的层数和该点单向连接,边为0;该点与相应层的邻层单向连接,边为c;这样可以解决上述同层联通的问题。
最后给出代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define N 200100
#define M 4001000
#define INF 0x3f3f3f3f
using namespace std;
struct node
{
int to,next,v;
}e[M];
int d[N],head[N],cnt,v[N],layer[N],c,n,m;
void add(int u,int v,int w)
{
e[cnt].to=v;
e[cnt].next=head[u];
e[cnt].v=w;
head[u]=cnt++;
}
void spfa()
{
for(int i=1;i<=2*n;i++)
d[i]=INF,v[i]=0;
d[1]=0;
v[1]=1;
queue<int>q;
q.push(1);
while(!q.empty())
{
int t=q.front();
q.pop();
v[t]=0;
for(int i=head[t];i!=-1;i=e[i].next)
{
int b=e[i].to,w=e[i].v;
if(d[b]>d[t]+w)
{
d[b]=d[t]+w;
if(!v[b])
{
v[b]=1;
q.push(b);
}
}
}
}
if(d[n]<INF)
cout<<d[n]<<endl;
else
cout<<-1<<endl;
}
int main()
{
int T;
cin>>T;
for(int kase=1;kase<=T;kase++)
{
cin>>n>>m>>c;
for(int i=1;i<=2*n;i++)
head[i]=layer[i]=-1;
for(int i=1;i<=n;i++)
{
scanf("%d",&layer[i]);
layer[n+layer[i]]=1;
}
cnt=0;
for(int i=0;i<m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
for(int i=1;i<n;i++)
if(layer[i+n]==1&&layer[i+n+1]==1)
add(i+n,i+n+1,c),add(i+n+1,i+n,c);
for(int i=1;i<=n;i++)
{
add(layer[i]+n,i,0);
if(layer[i]>1) add(i,layer[i]+n-1,c);
if(layer[i]<n) add(i,layer[i]+n+1,c);
}
printf("Case #%d: ",kase);
spfa();
}
}