AcWing 361. 观光奶牛

原题链接
考察:二分+SPFA
引入:形如 \({\sum_1^n f[i] \over \sum_1^n g[j]}\)求其最大值,称为01分数规划问题.通过二分最大值,检验解的存在性,这样的存在性具有单调性,所以可以用二分解决.
思路:
想到二分之后,我们可以假设最大值 = mid,对于每一个环,检验\({\sum_1^n f[i] \over \sum_1^n t[i]}\) >=mid 如果为true,就调大mid,否则mid变小.
如果寻找每一个环,时间复杂度应该是O(n2m*log2m)铁TLE,所以我们需要考虑优化.
首先必须整理式子,\(\sum_1^n f[i]\) >= mid*\(\sum_1^n t[i]\) 而这个等价于 \(\sum_1^n (f[i]-mid*t[i])\) 这个问题又等价于我们需要找到一个环,环的边权与点权符合上面的性质.此时如果我们把边的权值变成f[i] - mid*t[i]就转化为是否能在图中找到正环.

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 1010,M = 5010;
const double eps = 1e-6;
int n,h[N],m,score[N],idx,cnt[N];
bool st[N];
double dist[N];
struct Road{
    int fr,to,ne;
    double w;
    Road operator=(const Road& r){
        this->fr = r.fr;
        this->to = r.to;
        this->ne = r.ne;
        this->w = r.w;
        return *this;
    }
}road[M],path[M];
void add(int a,int b,double c)
{
    road[idx].w = c,road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++;
}
bool spfa()
{
    queue<int> q;
    for(int i=1;i<=n;i++)
    {
        st[i] = 1;
        dist[i] = cnt[i] = 0;
        q.push(i);
    }
    while(q.size())
    {
        int u = q.front();
        q.pop();
        st[u] = 0;
        for(int i=h[u];~i;i=road[i].ne)
        {
            int v = road[i].to;
            if(dist[v]<dist[u]+road[i].w)
            {
                dist[v] = dist[u]+road[i].w;
                cnt[v] = cnt[u]+1;
                if(cnt[v]>=n) return 1;
                if(!st[v]) q.push(v),st[v] = 1;
            }
        }
    }
    return 0;
}
bool check(double mid)
{
    for(int i=0;i<idx;i++) road[i] = path[i];
    for(int i=0;i<idx;i++)
    {
        int v = road[i].to;
        road[i].w = score[v] - mid*road[i].w;
    }
    if(spfa()) return 1;
    else return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&score[i]),h[i] = -1;
    while(m--)
    {
        int a,b; double w;
        scanf("%d%d%lf",&a,&b,&w);
        add(a,b,w);
    }
    for(int i=0;i<idx;i++) path[i] = road[i];
    double l = 0,r = 1010;
    while(r-l>=eps)
    {
        double mid = (l+r)/2;
        if(check(mid)) l = mid;
        else r = mid;
    }
    printf("%.2lf\n",r);
    return 0;
}	
上一篇:tyflow birth节点


下一篇:Layout POJ - 3169