bzoj 1486: [HNOI2009]最小圈 01分数规划

题目大意:

求有向带权图中的最小平均值圈,平均值定义为边的权和与点数的比值

题解:

标准的01分数规划

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
	x=0;char ch;bool flag = false;
	while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
	while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 3010;
const int maxm = 10010;
const double eps = 1e-12;
struct Edge{
	int to,next;
	double dis;
}G[maxm<<1];
int head[maxn],cnt;
void add(int u,int v,double d){
	G[++cnt].to = v;
	G[cnt].next = head[u];
	head[u] = cnt;
	G[cnt].dis = d;
}
#define v G[i].to
bool inq[maxn];double dis[maxn];
bool dfs(int u){
	inq[u] = true;
	for(int i = head[u];i;i=G[i].next){
		if(dis[v] > dis[u] + G[i].dis){
			dis[v] = dis[u] + G[i].dis;
			if(inq[v]) return true;
			if(dfs(v)) return true;
		}
	}inq[u] = false;
	return false;
}
#undef v
int n;
inline bool check(double mid){
	for(int i=1;i<=cnt;++i) G[i].dis -= mid;
	memset(inq,0,sizeof inq);memset(dis,0,sizeof dis);
	bool flag = false;
	for(int i=1;i<=n;++i) if(dfs(i)){flag = true;break;}
	for(int i=1;i<=cnt;++i) G[i].dis += mid;
	return flag;
}
int main(){
	int m;read(n);read(m);
	double d;
	for(int i=1,u,v;i<=m;++i){
		read(u);read(v);scanf("%lf",&d);
		add(u,v,d);
	}
	double l = -1e9,r = 1e9;
	while(r-l > eps){
		double mid = (l+r)/2;
		if(check(mid)) r = mid;
		else l = mid;
	}printf("%.8lf\n",r);
	getchar();getchar();
	return 0;
}
posted @ 2017-02-28 09:19  Sky_miner  阅读(155)  评论(0编辑  收藏  举报