判断给定的有向图中是否存在负环。
利用 spfa 算法判断负环有两种方法:
1) spfa 的 dfs 形式,判断条件是存在一点在一条路径上出现多次。
2) spfa 的 bfs 形式,判断条件是存在一点入队次数大于总顶点数。
http://poj.org/problem?id=3259
在探索他的许多农场时,农夫约翰发现了许多令人惊奇的虫洞。一个虫洞是非常奇怪的,因为它是一条单向的路径,在你进入虫洞之前的一段时间把你送到它的目的地!FJ的每个农场包括N(1≤)N≤500)方便地编号为1.N, M(1≤)M(≤2500)路径,以及W(1≤)W≤200)虫洞。
由于FJ是一个狂热的时间旅行迷,他想做以下几件事:从某个领域开始,穿过一些路径和虫洞,然后在他最初离开之前回到起点。也许他能认识自己:)。
为了帮助FJ找出这是否可能,他会向你提供完整的地图F(1≤)F≤5)他的农场。任何路径都不会超过10,000秒的行程,而且没有虫洞能使FJ及时返回超过10,000秒。
输入
第1行:一个整数,F. F农场的描述如下。
每个场的第1行:三个空格分隔的整数:N, M,和W
第2行.。M+一个农场:三个空格分隔的数字(S, E, T)分别描述:双向路径S和E这需要T再过几秒钟。两个字段可能由多条路径连接。
线M+2.. M+ W+一个农场:三个空格分隔的数字(S, E, T)分别描述:从S到E这也会让旅行者回来T几秒钟。
输出量
第1行.。F*对于每个农场,如果FJ能够实现他的目标,输出“是”,否则输出“否”(不包括引号)。
样本输入
2 3 3 1 1 2 2 1 3 4 2 3 1 3 1 3 3 2 1 1 2 3 2 3 4 3 1 8
样本输出
NO YES
BFS_SPFA版:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
struct node {
ll id;
ll d;
ll next_s;
}side[6000];
ll cnt,n,head[501],flag[501],dis[501],cn[501];
ll book;
void init(){
memset(head,-1,sizeof(head));
cnt=0;
}
void add(ll x,ll y,ll z){
side[cnt].id=y;
side[cnt].d=z;
side[cnt].next_s=head[x];
head[x]=cnt++;
}
ll bfs_spfa(){
memset(cn,0,sizeof(cn));//cn[i]记录i入队的次数
memset(dis,INF,sizeof(dis));//初始化dis
dis[1]=0;
queue<ll> p;
//压入那个点,看dis的含义
p.push(1);
flag[1]=1;
while(p.size()){
ll t=p.front();
p.pop();
flag[t]=0;
for(int i=head[t];i!=-1;i=side[i].next_s){
if(dis[side[i].id]>dis[t]+side[i].d){
dis[side[i].id]=dis[t]+side[i].d;
if(!flag[side[i].id]){
p.push(side[i].id);
flag[side[i].id]=1;
cn[side[i].id]++;
//接下来和求单源最短路的不同的地方
if(cn[side[i].id]>=n){ //关键不能是大于,是大于等于或等于
return 1;
}
}
}
}
}
return 0;
}
int main(){
ll f;
cin>>f;
while(f--){
memset(dis,INF,sizeof(dis));
memset(flag,0,sizeof(flag));
init();
ll m,w;
cin>>n>>m>>w;
for(int i=0;i<m;i++){
ll x,y,z;
cin>>x>>y>>z;
add(x,y,z);
add(y,x,z);
}
for(int i=0;i<w;i++){
ll x,y,z;
cin>>x>>y>>z;
add(x,y,z*(-1));
}
book=bfs_spfa();
if(book==1){
cout<<"YES"<<endl;
}
else cout<<"NO"<<endl;
}
return 0;
}
DFS_SPFA版:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
struct node {
ll id;
ll d;
ll next_s;
}side[6000];
ll cnt,n,head[501],flag[501],dis[501],cn[501];
ll book;
void init(){
memset(head,-1,sizeof(head));
cnt=0;
}
void add(ll x,ll y,ll z){
side[cnt].id=y;
side[cnt].d=z;
side[cnt].next_s=head[x];
head[x]=cnt++;
}
void dfs_spfa(ll x){
if(book)return ;
flag[x]=1;
for(int i=head[x];i!=-1;i=side[i].next_s){
if(book)
return ;
if(dis[side[i].id]>dis[x]+side[i].d){
dis[side[i].id]=dis[x]+side[i].d;
if(!flag[side[i].id]){
dfs_spfa(side[i].id);//side[i].id不在路径中,就继续扩展
}
else {
//如果side[i].id已经在路径上,则把book标记为1返回
book=1;
return ;
}
}
}
flag[x]=0;
}
int main(){
ll f;
cin>>f;
while(f--){
book=0;
memset(dis,INF,sizeof(dis));
memset(flag,0,sizeof(flag));
init();
ll m,w;
cin>>n>>m>>w;
for(int i=0;i<m;i++){
ll x,y,z;
cin>>x>>y>>z;
add(x,y,z);
add(y,x,z);
}
for(int i=0;i<w;i++){
ll x,y,z;
cin>>x>>y>>z;
add(x,y,z*(-1));
}
dis[1]=0;
dfs_spfa(1);
if(book==1){
cout<<"YES"<<endl;
}
else cout<<"NO"<<endl;
}
return 0;
}