#0/1分数规划+spfa负环# [luogu P2868] [USACO07DEC]Sightseeing Cows G

Title

P2868 [USACO07DEC]Sightseeing Cows G


Solution

∑ i = 1 t F [ i ] ∑ i = 1 t A [ i ] = a n s \frac{\sum_{i=1}^{t}F[i]}{\sum_{i=1}^{t}A[i]}=ans i=1tA[i]i=1tF[i]=ans
我们可以二分 a n s ans ans
∑ i = 1 t F [ i ] − ∑ i = 1 t A [ i ] ∗ m i d > 0 \sum_{i=1}^{t}F[i]-\sum_{i=1}^{t}A[i]*mid>0 i=1tF[i]i=1tA[i]mid>0
∑ i = 1 t A [ i ] ∗ m i d − ∑ i = 1 t F [ i ] < 0 \sum_{i=1}^{t}A[i]*mid-\sum_{i=1}^{t}F[i]<0 i=1tA[i]midi=1tF[i]<0
可以用 s p f a spfa spfa来判定负环。
r − l r-l rl达到一定的精度后就退出


Code

#include
#include
#include
#define db double
#define rep(i,x,y) for(register int i=x;i<=y;i++)
using namespace std; 
const int N=1005; 
struct node{
	int y,z,next; 
}a[N*10];
int tot,head[N]; 
int n,m,b[N]; 
void add(int x,int y,int z){
	a[++tot]=(node){y,z,head[x]}; head[x]=tot; 
}
bool v[N]; db d[N]; int w[N]; 
bool check(db k){
	queue<int>q; 
	rep(i,1,n) q.push(i),d[i]=0,w[i]=1,v[i]=1; 
	while (q.size()){
		int x=q.front(); q.pop(); v[x]=0;
		for(int i=head[x];i;i=a[i].next){
			int y=a[i].y; db dis=(db)a[i].z; 
			if (d[y]>d[x]+k*dis-(db)b[x]){
				d[y]=d[x]+k*dis-(db)b[x]; 
				if (!v[y]){
					q.push(y),v[y]=1; 
					if (++w[y]>=n) return 1; 
				} 
			}
		}
	}
	return 0; 
}
int main(){
	scanf("%d%d",&n,&m); 
	rep(i,1,n) scanf("%d",&b[i]); 
	rep(i,1,m){
		int x,y,z; 
		scanf("%d%d%d",&x,&y,&z); 
		add(x,y,z); 
	}
	db l=0,r=1000010,mid; 
	while (r-l>1e-4){
		mid=(l+r)/2; 
		if (check(mid)) l=mid; else r=mid; 
	}
	printf("%.2lf",l); 
	return 0; 
}

你可能感兴趣的:(0/1分数规划,最短路径)