判环

\(SPFA\)判负环

亲身试验\(dfs\)过不了,会被卡成\(n^n\)。传统\(spfa\),判断一个点的入队次数,超过\(n\)就有负环

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int read(){
	int x=0;int f=0;char c=getchar();
	while(c<'0'||c>'9')f|=c=='-',c=getchar();
	while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return f?-x:x;
}
int n,m,T,head[200005],dis[200005],num,q[20000000],h,t,in[200005];
bool vis[200005],flag;
struct node{
    int to,next,w;
}a[400005];
bool SPFA(){
    memset(dis,0x3f3f3f3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(in,0,sizeof(in));
    memset(q,0,sizeof(q));
    dis[1]=0,h=t=0;
    q[++t]=1;
    while(h<=t){
    	int u=q[++h];vis[u]=0;
    	if(in[u]>n) return 1;
    	for(int i=head[u],v;v=a[i].to,i;i=a[i].next){
    		if(dis[v]>dis[u]+a[i].w){
    			dis[v]=dis[u]+a[i].w,in[v]=in[u]+1;
    			if(in[v]>n) return 1;
    			if(!vis[v]) q[++t]=v,vis[v]=1;
			}
		}
	}
	return 0;
}
int main(){
    T=read();
    while(T--){
        n=read(),m=read();num=0;
        memset(head,0,sizeof(head));
        for(int x,y,w,i=1;i<=m;i++){
            x=read(),y=read(),w=read();
            a[++num].to=y,a[num].next=head[x],a[num].w=w,head[x]=num;
            if(w>=0) a[++num].to=x,a[num].next=head[y],a[num].w=w,head[y]=num;
        }
        if(SPFA()) printf("YE5\n");
        else printf("N0\n");
    }
    return 0;
}

\(Floyed\)无向图求最小环

#include<iostream>
#include<cstring>
using namespace std;
const int inf(0x1f1f1f1f) ;
int n,m,map[105][105],d[105][105],ans=inf,what[3],p[105][105];
void print(int x,int y){
	if(!p[x][y]) cout<<x<<' ';//如果x不能到y,输出x 
	else print(x,p[x][y]),print(p[x][y],y);
}
int main(){
	scanf("%d%d",&n,&m);
	memset(map,0x1f,sizeof map);
	memset(d,0x1f,sizeof d);
	for(int i=1,x,y,z;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		d[x][y]=d[y][x]=map[x][y]=map[y][x]=min(map[y][x],z);//建图 
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<k;i++)
			for(int j=i+1;j<k;j++)
				if(d[i][j]+map[i][k]+map[k][j]<ans){
					ans=d[i][j]+map[i][k]+map[k][j];//更新最小环的答案 
					what[0]=k,what[1]=i,what[2]=j;//从i到j中间经过k 
				}
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)//最短路 
				if(d[i][j]>d[i][k]+d[k][j])
					d[i][j]=d[i][k]+d[k][j],p[i][j]=k;//从i到j的最短路经过k
	}
	if(ans==inf) cout<<"No solution.";
	else print(what[1],what[2]),cout<<what[2]<<' '<<what[0];
	return 0;
}

欢迎指正评论O(∩_∩)O~~

posted @ 2018-10-30 19:38  Kylin_Seven  阅读(158)  评论(0)    收藏  举报