poj 3621 Sightseeing Cows 01分数规划

题目大意:

http://poj.org/problem?id=3621

题解:

首先我们容易发现最优的路线一定只经过一个环。
所以我们可以把点权合并到边权上.
然后就转化为了一个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 = 1024;
const int maxm = 5010;
const double eps = 1e-6;
inline int dcmp(const double &x){
	if(x < eps && x > -eps) return 0;
	return x > 0 ? 1 : -1;
}
struct Edge{
	int to,next,d;
	double dis;
}G[maxm<<1];
int head[maxn],cnt;
void add(int u,int v,int d){
	G[++cnt].to = v;
	G[cnt].next = head[u];
	head[u] = cnt;
	G[cnt].d = d;
}
double dis[maxn];
bool inq[maxn];
#define v G[i].to
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 w[maxn],n,m;
inline bool check(double mid){
	memset(inq,0,sizeof inq);
	memset(dis,0,sizeof dis);
	for(int i=1;i<=cnt;++i)
		G[i].dis = mid*G[i].d - w[G[i].to];
	for(int i=1;i<=n;++i) 
		if(dfs(i)) return true;
	return false;
}
int main(){
	read(n);read(m);
	for(int i=1;i<=n;++i) read(w[i]);
	for(int i=1,u,v,d;i<=m;++i){
		read(u);read(v);read(d);
		add(u,v,d);//add(v,u,d);
	}
	double l = .0,r = 1e9;
	while((r-l) > eps){
		double mid = (l+r)/2;
		if(check(mid)) l = mid;
		else r = mid;
	}printf("%.2lf
",l);
	getchar();getchar();
	return 0;
}
原文地址:https://www.cnblogs.com/Skyminer/p/6475845.html