思路:
-
Dijkstra,正权,双向(隐藏单向),最短路。
-
首先我以为是同一层中的点之间距离全部为零,结果WA了。仔细想一遍题意:对某一层中的所有点任意选取一点,都可以从该点,花费C到达相邻层中的任意一点,并没有说同一层间的距离呀。
-
正确题意:对任意一点(属于 A 层):
-
它若想到该层中其它点有两种方法:
通过 M extra edges,直接达到;
先去到某相邻层 B,然后回到本层 A 的其它点(根据代码:任意去到B层中的某点,再从该点回到A层,再从 A 层回到起始点)。
-
它若想去到其它层的某点有两种方法:
通过 M extra edges,直接达到;
先达到目标层的某相邻层,然后花费 C,可去到目标层中的任一点。
-
-
注意:( 隐藏单向 )本代码中跨层时,只可以建抽象点(层)到所属点的路,不可以建所属点到抽象层的路。原因见注释。
代码:
- 理解错题意(想简单了):WA
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 100005;
int T;
int N,M,C;
struct EDGE{
int to;
int w;
int fo;
};
EDGE E[maxn * 4];
int tail[maxn];
void ADDEDGE(int i,int u,int v,int w){
E[i].to = v;
E[i].w = w;
E[i].fo = tail[u];
tail[u] = i;
return ;
} int cnt;
int dis[maxn];
int L[maxn];//layer exact
bool LB[maxn];//book if been here
struct NODE{
int id;
int dis;
NODE(int id,int dis) : id(id) , dis(dis) {} ;
friend bool operator > (NODE a,NODE b){
return a.dis > b.dis ;
}
};
priority_queue<NODE , vector<NODE> , greater<NODE> > Q;
void INIT(){
memset(tail,-1,sizeof(tail));
memset(dis,INF,sizeof(dis));
memset(L,0,sizeof(L));
memset(LB,0,sizeof(LB));
cnt=0;//from 1 .. cnt
return ;
}
int IJK(){
Q.push(NODE(L[1],0));dis[L[1]]=0;
while(Q.size()){
NODE cur = Q.top() ; Q.pop() ;
if(cur.dis > dis[cur.id])
continue;
for(int i=tail[cur.id] ; ~i ; i=E[i].fo){
int v = E[i].to;
if(dis[v] > dis[cur.id] + E[i].w){
dis[v] = dis[cur.id] + E[i].w;
Q.push(NODE(v,dis[v]));
}
}
}
if(dis[L[N]] == INF)
return -1;
else
return dis[L[N]];
}
int main(){
scanf("%d",&T);
for(int t=1;t<=T;t++){
INIT();
scanf("%d%d%d",&N,&M,&C);
for(int i=1;i<=N;i++){
scanf("%d",L+i);
LB[L[i]] = true;
}
for(int i=1;i<N;i++){
if(LB[i] && LB[i+1]){
ADDEDGE(++cnt,i,i+1,C);
ADDEDGE(++cnt,i+1,i,C);
}
}
for(int i=1;i<=M;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
ADDEDGE(++cnt,L[u],L[v],w);
ADDEDGE(++cnt,L[v],L[u],w);
}
printf("Case #%d: %d\n",t,IJK());
}
return 0;
}
- 将层变成抽象点:358ms 10736kB
//358ms 10736kB
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 100005 * 2;//如果每层只有一个点。
int T;
int N,M,C;
struct EDGE{
int to;
int w;
int fo;
};
EDGE E[maxn * 3];//实际是2.5
int tail[maxn];
void ADDEDGE(int i,int u,int v,int w){
E[i].to = v;
E[i].w = w;
E[i].fo = tail[u];
tail[u] = i;
return ;
} int cnt;
int dis[maxn];
int L[maxn];//layer exact
bool LB[maxn];//book if been here
struct NODE{
int id;
int dis;
NODE(int id,int dis) : id(id) , dis(dis) {} ;
friend bool operator > (NODE a,NODE b){
return a.dis > b.dis ;
}
};
priority_queue<NODE , vector<NODE> , greater<NODE> > Q;
void INIT(){
memset(tail,-1,sizeof(tail));
memset(dis,INF,sizeof(dis));
memset(L,0,sizeof(L));
memset(LB,0,sizeof(LB));
cnt=0;//from 1 .. cnt
return ;
}
int IJK(){
Q.push(NODE(1,0));dis[1]=0;
while(Q.size()){
NODE cur = Q.top() ; Q.pop() ;
if(cur.dis > dis[cur.id])
continue;
for(int i=tail[cur.id] ; ~i ; i=E[i].fo){
int v = E[i].to;
if(dis[v] > dis[cur.id] + E[i].w){
dis[v] = dis[cur.id] + E[i].w;
Q.push(NODE(v,dis[v]));
}
}
}
if(dis[N] == INF)
return -1;
else
return dis[N];
}
int main(){
scanf("%d",&T);
for(int t=1;t<=T;t++){
INIT();
scanf("%d%d%d",&N,&M,&C);
for(int i=1;i<=N;i++){
scanf("%d",L+i);
LB[L[i]] = true;//1 .. N
/*
ADDEDGE(++cnt,i,N+L[i],0);//点 i 到 N + L[i]层
ADDEDGE(++cnt,N+L[i],i,0);//如果再建一条反向边,那同层的距离都变成0了。
*/
ADDEDGE(++cnt,N+L[i],i,0);
//只建层到点的边,点如果想去别的层,让它直接连过去(点->邻层)。
}
for(int i=1;i<=N;i++){
if(L[i] + 1)
ADDEDGE(++cnt,i,N+L[i]+1,C);
if(L[i] - 1)
ADDEDGE(++cnt,i,N+L[i]-1,C);
}
for(int i=1;i<=M;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
ADDEDGE(++cnt,u,v,w);
ADDEDGE(++cnt,v,u,w);
}
printf("Case #%d: %d\n",t,IJK());
}
return 0;
}