如果按照自己建图点个数为(N^2) 明显这个复杂度是不行的,过后,可以把每一层分成上个层进入点,和到下层的进入点,只需要把某一个边变成C就可以了,比赛的时候收惨写了2个u 到 v 没写v 到u 开始的时候tle了,然后单调队列优化了下 ,就worng 了 结果wrong了一下午,后面发现有些层没点,但是自己的代码考虑到了,晚上才ac哎,
#include<cstdio>
#include<cstring>
#include<queue>
#include<deque>
#define inf 0x3f3f3f3f
#define M 700000
#define ll int
using namespace std;
struct G{
ll head[M],en;
struct E{
ll u,v,next,cost;
}e[M<<2];
void init(){
memset(head,-1,sizeof(head));en=0;
}
void add(ll u,ll v,ll cost){
e[en].u=u;e[en].v=v;e[en].cost=cost;e[en].next=head[u];head[u]=en++;
}
}g1;
ll dis[M];
bool vis[M];
ll realx(ll v,ll u,ll cost){
if(dis[v]>dis[u]+cost){
dis[v]=dis[u]+cost;
return 1;
}
return 0;
}
deque<ll > q1;
ll spfa(ll sp,ll tp){
memset(vis,1,sizeof(vis));
memset(dis,inf,sizeof(dis));
while(!q1.empty()) q1.pop_front();
q1.push_back(sp);
dis[sp]=0;vis[sp]=0;
while(!q1.empty()){
ll u=q1.front();q1.pop_front();
for(ll i=g1.head[u];~i;i=g1.e[i].next){
ll v=g1.e[i].v;ll cost=g1.e[i].cost;
if(realx(v,u,cost)){
if(vis[v]){
vis[v]=0;
if(!q1.empty()){
ll t1=q1.front();
if(dis[v]<dis[t1])
q1.push_front(v);
else q1.push_back(v);
}else q1.push_back(v);
}
}
}
vis[u]=1;
}
return dis[tp];
}
bool can_use[M];
int a1[M];
int main(){
ll n,m,c,cas;
while(~scanf("%d",&cas)){
for(ll q=1;q<=cas;q++){
scanf("%d%d%d",&n,&m,&c);
g1.init();
memset(can_use,0,sizeof(can_use));
for(ll i=1;i<=n;i++){
ll t1;scanf("%d",&t1);
a1[i]=t1;
g1.add(t1+n,i,c); //入边
g1.add(i,t1+2*n,c);// 出边
can_use[t1]=1;
}
for(int i=1;i<=n;i++){
int t1=a1[i];
if(t1==1) continue;
if(can_use[t1-1]){
g1.add(t1+2*n-1,i,0); //上层边点
g1.add(i,t1+n-1,0); // 上层入边
}
}
for(ll i=0;i<m;i++){
ll u,v,cost;scanf("%d%d%d",&u,&v,&cost);
g1.add(u,v,cost);g1.add(v,u,cost);
}
ll ans=spfa(1,n);
printf("Case #%d: ",q);
if(ans!=dis[M-1])
printf("%d\n",ans);
else printf("-1\n");
}
}
return 0;
}
/*
3
3 0 1
1 1 1
*/