bzoj1486【HNOI2009】最小圈

1486: [HNOI2009]最小圈

Time Limit: 10 Sec  Memory Limit: 64 MB

Submit: 1778  Solved: 827

[Submit][Status][Discuss]

Description

Input

Output

Sample Input

Sample Output

HINT

Source

01分数规划+二分答案+spfa判负环

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 3005
#define maxm 10005
#define inf 1000000000
#define eps 1e-9
using namespace std;
struct edge{int next,to;double v,w;}e[maxm];
int n,m,cnt,head[maxn];
double dis[maxn];
bool flag,mark[maxn];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void add_edge(int x,int y)
{
	e[++cnt].next=head[x];
	e[cnt].to=y;
	head[x]=cnt;
}
inline void spfa(int x)
{
	if (mark[x]){flag=true;return;}
	mark[x]=true;
	for(int i=head[x],y;i;i=e[i].next)
		if (dis[x]+e[i].v<dis[y=e[i].to])
		{
			dis[y]=dis[x]+e[i].v;
			spfa(y);
			if (flag) return;
		}
	mark[x]=false;
}
inline bool judge()
{
	F(i,1,n) dis[i]=mark[i]=0;
	flag=false;
	F(i,1,n)
	{
		spfa(i);
		if (flag) return true;
	}
	return false;
}
int main()
{
	n=read();m=read();
	int x,y;double z,l=inf,r=-inf,mid;
	F(i,1,m)
	{
		x=read();y=read();scanf("%lf",&z);
		add_edge(x,y);
		e[i].w=z;
		l=min(l,z);
		r=max(r,z);
	}
	while (r-l>=eps)
	{
		mid=(l+r)/2;
		F(i,1,m) e[i].v=e[i].w-mid;
		if (judge()) r=mid;
		else l=mid;
	}
	printf("%.8lf\n",l);
	return 0;
}
时间: 2024-12-30 16:18:06

bzoj1486【HNOI2009】最小圈的相关文章

BZOJ1486 [HNOI2009]最小圈

今年的最后一篇了呢...好伤感的说,2014年还有1h就过去了 不不不回到正题,这道题嘛~看上去好神啊! 看到此题,我们可以联想到最优比例MST,于是就有了方法: 首先二分答案ans,判断ans是否可行,那如何判断呢? 每条边边权 - ans,之后在新的图中找负环即可.(可以用dfs版的spfa) 1 /************************************************************** 2 Problem: 1486 3 User: rausen 4 L

1486: [HNOI2009]最小圈 - BZOJ

在机房的小伙伴提醒是二分之后,我想到了是判负环,所以我用spfa,而且我保持dis都是小于等于0,本以为这样就能过了,可是还是有一个点达到了3.8s左右(其他都是0.0几秒) 所以还是写了dfs版本,还是一样每次都保持dis小于等于0,当发现有一个点在栈中,你又可以更新他的dis,那么就有负环了 1 const 2 maxn=3010; 3 maxm=10010; 4 inf=99999; 5 var 6 first:array[0..maxn]of longint; 7 next,last:a

bzoj 1486: [HNOI2009]最小圈 dfs求负环

1486: [HNOI2009]最小圈 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1022  Solved: 487[Submit][Status] Description 最开始写floyd求负环结果TLE了,改成dfs后速度变成原来的100+倍.反正还是比较神奇.

[HNOI2009]最小圈

hnoi2009最小圈 Description #include<iostream> #include<cstdio> #include<cstring> #define maxn 3005 #define maxe 10005 using namespace std; struct Edge { int v; double w; int next; }e[maxe]; int head[maxn],cnts=0,n,m; double eps=1e-9,dis[max

BZOJ 1486: [HNOI2009]最小圈( 二分答案 + dfs判负圈 )

二分答案m, 然后全部边权减掉m, 假如存在负圈, 那么说明有平均值更小的圈存在. 负圈用dfs判断. --------------------------------------------------------------------------- #include<bits/stdc++.h> #define rep(i, n) for(int i = 0; i < n; ++i) #define clr(x, c) memset(x, c, sizeof(x)) #define

bzoj千题计划227:bzo1486: [HNOI2009]最小圈j

http://www.lydsy.com/JudgeOnline/problem.php?id=1486 二分答案 dfs版spfa判负环 #include<queue> #include<cstdio> #include<cstring> #include<iostream> #define N 3001 #define M 10001 using namespace std; int n; int tot,front[N],nxt[M],to[M]; d

【bzoj1486】 HNOI2009—最小圈

http://www.lydsy.com/JudgeOnline/problem.php?id=1486 (题目链接) 题意:给出一张有向图,规定一个数值u表示图中一个环的权值/环中节点个数.求最小的u. Solution  尼玛今天考试题,不知道是考二分的话这真的做不出..  二分一个答案ans,这个答案可行当且仅当ans>=∑w/cnt,cnt表示环中节点个数.移项,ans*cnt-∑w>=0,而w的个数又正好等于cnt,所以最后的式子变成了: ∑i=0n(ans−w)>=0 这个式

【bzoj1486】[HNOI2009]最小圈 分数规划+Spfa

题目描述 样例输入 4 5 1 2 5 2 3 5 3 1 5 2 4 3 4 1 3 样例输出 3.66666667 题解 分数规划+Spfa判负环 二分答案mid,并将所有边权减去mid,然后再判负环,若有负环则调整下界,否则调整上界,直至上下界基本重合. 证明:显然 由于有(c+d)/(a+b+k)>(c+d)/(a+b)≥min(c/a,d/b),所以两个相交环形成的新环一定不是最优解,即答案一定是简单环. 如果存在环使得边权和/点数<mid,那么就有边权和<点数*mid. 又因

【dfs判负环】BZOJ1489: [HNOI2009]最小圈

Description 找出一个平均边权最小的圈. Solution 经典问题,二分答案判断有无负环. 但数据范围大,普通spfa会超时,于是用dfs判负环(快多了). 思路是dis设为0,枚举每个点u,如果d(u)+w<d(v)就搜v,如果搜到的节点曾搜到过说明找到了负环. 感慨一下dfs真是神奇. Code 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespac

bzoj 1486: [HNOI2009]最小圈

二分答案再判负环 #include<cstdio> #include<algorithm> using namespace std; int read_p,read_ca; inline int read(){ read_p=0;read_ca=getchar(); while(read_ca<'0'||read_ca>'9') read_ca=getchar(); while(read_ca>='0'&&read_ca<='9') read