BZOJ 1486: [HNOI2009]最小圈

平均值最小回路

二分答案后把每条边的权值都减去答案

然后spfa判负圈

果断TLE

参照09年论文改成DFS版的SPFA,AC

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
const int N=3000+5;
const int M=10000+5;
const double eps=1e-9;
struct Edge{int to,next;double v;}e[M];
int head[N],cnt;
void ins(int u,int v,double w){
	e[++cnt]=(Edge){v,head[u],w};head[u]=cnt;
}
double d[N];
bool inq[N];
int n,m;
bool spfa(int u){
	inq[u]=1;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(d[v]>d[u]+e[i].v){
			if(inq[v])return true;
			else{
				d[v]=d[u]+e[i].v;
				if(spfa(v))return true;
			}
		}
	}
	inq[u]=0;
	return false;
}
bool check(){
	for(int i=1;i<=n;i++)
	if(spfa(i))return true;
	return false;
}
bool check(double x){
	memset(d,0,sizeof(d));
	memset(inq,0,sizeof(inq));
	for(int i=1;i<=cnt;i++)e[i].v-=x;
	bool ans=check();
	for(int i=1;i<=cnt;i++)e[i].v+=x;
	return ans;
}
int main(){
	//freopen("a.in","r",stdin);
	scanf("%d%d",&n,&m);
	double l=1e60,r=-(1e60);
	while(m--){
		int u,v;double w;
		scanf("%d%d%lf",&u,&v,&w);
		ins(u,v,w);
		l=min(l,w);
		r=max(r,w);
	}
	while(r-l>1e-9){
		double mid=(l+r)/2.0;
		if(check(mid))r=mid;
		else l=mid;
	}
	printf("%.8lf\n",l);
	return 0;
}


你可能感兴趣的:(BZOJ 1486: [HNOI2009]最小圈)