题目描述
在一个神秘岛上,有N(1 <= N <= 500)个洞口,标号1..N,它们之间有M (1 <= M <= 2500) 条通道相连。神秘的竟然另外还有W (1 <= W <=200)条传说中的时间虫洞—-当到达通道的另一端洞口时,竟然可以比进入的时间要早!
你当然想进行这样的时间之旅,希望从一个洞口s出发,经过几个通道,在比出发早些时候的时间回到洞口s。也许还能碰到自己呢,hehe 根据给定的地图,请判断能否实现这样的愿望。
输入格式
第一行:一个整数 F (1 <= F <= 5),表示共有F组数据。(多组数据测试)每组数据: 第1行:三个整数 N M W
第2至M+1行:每行三个整数 (S, E, T),表示在S与E洞口之间有一个双向通道,通过需要T(0 <= T <= 10,000) 秒。
第M+2至M+W+1行:每行三个整数 (S, E, T),表示在S与E洞口之间有一个单向通道,从S到E可以回到之前T(0 <= T <= 10,000) 秒。
输出格式
共1..F行,每行对应一组数据,如果可以实现愿望输出”YES”,否则输出”NO”.
①bellman-ford
若无负权回路,迭代n-1次可得出最短路。故若迭代n-1次仍未得出,即存在负权回路。
int bmf()
{
memset(dis,10,sizeof(dis));
dis[1]=0;
for(int i=1;i<=n;++i)
{
int flag=0;
for(int j=1;j<=m*2+w;++j)
if(dis[e[j].q]+e[j].v<dis[e[j].z])
dis[e[j].z]=dis[e[j].q]+e[j].v;
if(!flag) return 0;//得出最短路即返回0,无负权回路。
}//有可能迭代n-1次恰好得最短路,故i应循环n次才可判断。
return 1;
}
②SPFA
两种思路。
1.因为最多迭代n-1次,故每个点最多被更新n-1次,即进队次数。若大于n-1,则存在负权回路。
void spfa()
{
memset(in,0,sizeof(in));//进队次数
memset(dis,10,sizeof(dis));
memset(vis,0,sizeof(vis));
flag=0;
int head=0,tail=0;
q[++tail]=1;
in[1]=1;
vis[1]=1;
dis[1]=0;
while(head++<tail)
{
for(int i=linkk[q[head]];i;i=e[i].next)
if(dis[e[i].y]>dis[q[head]]+e[i].v)
{
dis[e[i].y]=dis[q[head]]+e[i].v;
if(!vis[e[i].y]) {
q[++tail]=e[i].y;vis[e[i].y]=1;in[e[i].y]++;
if(in[e[i].y]==n){
flag=1;return;
}
}
}
vis[q[head]]=0;
}
}
2.最短路最多有n-1条路径。记录到某点的最短路包含的路径条数,若路径条数>n-1,即有负权回路。
void spfa()
{
memset(vis,0,sizeof(vis));
memset(path,0,sizeof(path));
memset(dis,10,sizeof(dis));
int head=0,tail=0;
flag=0;
q[++tail]=1;
vis[1]=1;
dis[1]=0;
while(head++<tail)
{
for(int i=linkk[q[head]];i;i=e[i].next)
if(dis[e[i].y]>dis[q[head]]+e[i].v)
{
path[e[i].y]=path[q[head]]+1;//若点A能更新点B,则源点至B路径条数为至A条数+1.
dis[e[i].y]=dis[q[head]]+e[i].v;
if(path[e[i].y]==n){
flag=1;return;
}
if(!vis[e[i].y]) q[++tail]=e[i].y,vis[e[i].y]=1;
}
vis[q[head]]=0;
}
}
相较之下应是SPFA的第二种方法效率较高。因为若存在环,第一种思想将这个环跑了n遍方可得出。而第二种仅需跑一遍。
这题用SPFA坑好**多啊。多组数据,dis、vis、path、flag要初始化,邻接表的计数器和link也要初始化。
啊。