题目链接[USACO07DEC]Sightseeing Cows G - 洛谷
01分数规划问题简单说来就是给你一堆物品,每件物品有两个属性a,b。每个物品都有选或不选两种情况,设定一个参数x[i],当x[i] = 0时代表物品i不选,x[i] = 1时代表物品选。我们需要从中取出若干物品,也就是求出
的最值,我们移一下项,式子变成了
求出满足式子的R的最(大/小)值
提公因式得到
我们可以发现,式子左边的值是随着R的增大而减小的。
我们以求最大值为例,对于一个确定的R值,当左边的式子的值大于零时,说明有更大的R使得式子更接近0,就可以用二分来做。//别人博客里的,拿来用一下
这题中的 R 就是奶牛平均乐趣值要求的最大值,a[i]是每个点的乐趣值,b[i]是各个道路所耗费的时间,再利用SPFA求负环的技巧求出图中的正环(因为是求最大值,所以找正环),二分以下即可求解
还有注意精度 l与r的差值应该在0.0001之间
AC代码如下
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
int n,m,idx;
int e[5010],ne[5010],wi[5010],h[5010],wj[1010];
double dist[1010];
bool vis[1010];
int cnt[1010];
void add(int a,int b,int c)
{
idx++;
e[idx]=b;
wi[idx]=c;
ne[idx]=h[a];
h[a]=idx;
}
bool check(double mid)
{
memset(dist,0,sizeof(dist));
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
queue<int> q;
for(int i=1;i<=n;i++) q.push(i),vis[i]=false;
while(q.size())
{
int k=q.front();
q.pop();
vis[k]=false;
for(int i=h[k];i;i=ne[i])
{
int j=e[i];
if(dist[j]<dist[k]+wj[k]-mid*wi[i])
{
dist[j]=dist[k]+wj[k]-mid*wi[i];
cnt[j]=cnt[k]+1;
if(cnt[j]>=n) return true;
if(!vis[j])
{
q.push(j);
vis[j]=true;
}
}
}
}
return false;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&wj[i]);
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
double r=1000,l=0;
while(r-l>1e-4)
{
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%.2lf",l);
return 0;
}