Description
在忘记考虑负环之后,黎瑟的算法又出错了。对于边带权的有向图 G = (V, E),请找出一个点数最小的环,使得
环上的边权和为负数。保证图中不包含重边和自环。
Input
第1两个整数n, m,表示图的点数和边数。
接下来的m行,每<=三个整数ui, vi, wi,表<=有一条从ui到vi,权值为wi的有向边。
2 <= n <= 300
0 <= m <= n(n <= 1)
1 <= ui, vi <= n
|wi| <= 10^4
Output
仅一行一个整数,表示点数最小的环上的点数,若图中不存在负环输出0。
Sample Input
3 6
1 2 -2
2 1 1
2 3 -10
3 2 10
3 1 -10
1 3 10
Sample Output
2
这道题可以二分答案,先二分负环点数,然后用dfs版SPFA限制经过点数判断是否存在负环即可,下面是程序:
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int N=305;
struct edge{
int v,w,next;
}e[N*N];
int head[N],dis[N],k,n;
bool vis[N],f;
void add(int u,int v,int w){
e[++k]=(edge){v,w,head[u]};
head[u]=k;
}
void SPFA(int u,int h,int &mx){
if(f){
return;
}
int i=head[u],v;
while(i){
v=e[i].v;
if(dis[u]+e[i].w<=dis[v]){
if(vis[v]){
f=1;
return;
}
if(h==mx){
return;
}
dis[v]=dis[u]+e[i].w;
vis[v]=1;
SPFA(v,h+1,mx);
vis[v]=0;
}
i=e[i].next;
}
}
bool check(int &k){
f=0;
int i;
for(i=1;i<=n&&!f;i++){
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
vis[i]=1;
SPFA(i,1,k);
}
return f;
}
int main(){
int m,l,r,w;
scanf("%d%d",&n,&m);
while(m--){
scanf("%d%d%d",&l,&r,&w);
add(l,r,w);
}
if(!check(n)){
printf("0");
return 0;
}
l=1,r=n;
while(l<r){
m=l+r>>1;
if(check(m)){
r=m;
}
else{
l=m+1;
}
}
printf("%d\n",l);
return 0;
}