POJ 3621 Sightseeing Cows(最优比率环+spfa的dfs判环优化)

题目链接
题目大意:给你一个有向图,每个点都有一个权值,每条边都有一个长度,需要找到一个各点权值和/各边长度和 最大的环出来,输出这个比值。
分析:假设结点权值为 w i w_i wi,边的长度为 l i l_i li设所求的比值 r = ∑ i = 1 m w v i ∗ x i ∑ i = 1 m l i ∗ x i ( x i = 0 或 1 , 1 < i < m ) r=\frac{\sum_{i=1}^{m}w_{vi}*x_i}{\sum_{i=1}^ml_i*x_i}(x_i=0或1,1<i<m) r=i=1mlixii=1mwvixi(xi=01,1<i<m)我们要最大化这个 r r r假设这个最大值为ans
则满足以下式子 a n s > = ∑ i = 1 m w v i ∗ x i ∑ i = 1 m l i ∗ x i ans>=\frac{\sum_{i=1}^{m}w_{vi}*x_i}{\sum_{i=1}^ml_i*x_i} ans>=i=1mlixii=1mwvixi
移项可得 ∑ i = 1 m w v i ∗ x i − a n s ∗ ∑ i = 1 m l i ∗ x i < = 0 \sum_{i=1}^{m}w_{vi}*x_i-ans*\sum_{i=1}^ml_i*x_i<=0 i=1mwvixiansi=1mlixi<=0
我们设 f ( a n s ) = ∑ i = 1 m w v i ∗ x i − a n s ∗ ∑ i = 1 m l i ∗ x i f(ans)=\sum_{i=1}^{m}w_{vi}*x_i-ans*\sum_{i=1}^ml_i*x_i f(ans)=i=1mwvixiansi=1mlixi
f ( a n s ) = ∑ i = 1 m d i ∗ x i , ( d i = w v i − a n s ∗ l i ) f(ans)=\sum_{i=1}^md_i*x_i,(d_i=w_{vi}-ans*l_i) f(ans)=i=1mdixi,(di=wviansli)
这个关于ans的函数是随ans变大而减小的,当f<=0时满足条件,当且仅当f=0时ans取得最大值,则我们就可以把每条边的权值设为 d i d_i di,然后二分ans,当用当前ans算出的f>0时则表明ans过小且不合法,当f<0时说明ans过大,而题目中要求的是一个环,当f<=0时是满足题意的,但我们不好判断,所以我们选择去判断f>0即图中存在正环。
判正环的算法可以用朴素的spfa也可dfs优化,最终的时间是朴素的是900+ms,而dfs优化则是30+ms
下面是dfs优化的

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#define MAIN main
#define PII pair<int,int>
#define x first
#define y second
using namespace std;
typedef long long ll;
const double eps=1e-8;
const double pi=acos(-1.0);
const int inf=0x3f3f3f3f;
const int N=1e3+10,M=5e3+10;
struct edge
{
    
    
    int v,next,w;
    double d;
}e[M<<1];
int head[N],cnt;
void add(int u,int v,int w)
{
    
    
    e[++cnt].v=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt;
}
int w[N],n,m,vis[N],ok;
double dis[N];
void dfs(int u)
{
    
    
    if(ok) return;
    vis[u]=1;
    for(int i=head[u];i;i=e[i].next)
    {
    
    
        int v=e[i].v;
        if(dis[v]<dis[u]+e[i].d)
        {
    
    
            dis[v]=dis[u]+e[i].d;
            if(vis[v])
            {
    
    
                ok=1;
                return;
            }
            dfs(v);
        }
    }
    vis[u]=0;
}
bool judge(double mid)
{
    
    
    for(int i=1;i<=cnt;i++) e[i].d=w[e[i].v]*1.0-mid*(e[i].w*1.0);
    for(int i=1;i<=n;i++) vis[i]=0,dis[i]=0;
    ok=0;
    for(int i=1;i<=n;i++){
    
    
        if(!vis[i]) dfs(i);
        if(ok) return true;
    }
    return false;
}
int MAIN()
{
    
    
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    for(int i=1;i<=m;i++){
    
    
        int u,v,l;
        scanf("%d%d%d",&u,&v,&l);
        add(u,v,l);
    }
    double l=0,r=1e6,mid,ans;
    while(r-l>0.0001)
    {
    
    
        mid=(l+r)/2;
        if(judge(mid)) l=mid;
        else ans=mid,r=mid;
    }
    printf("%.2f\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/amazingee/article/details/113614039
今日推荐