最优比率环(最优比率问题)

本文解析了如何通过01分数规划的原理解决在有权重和边权的图中寻找比率最大环的问题。讲解了如何调整新权值并利用SPFA进行求解,以及如何通过迭代找到最优比例。实例以SightseeingCows问题为例,展示了整个求解过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最优比率环:

给定有点权边权的图,要求找一个环,使环的点权和边权和的比值最大。

解决方法: 和01分数规划类似,但新权值的式子有所不同。在这里插入图片描述在这里插入图片描述来源:https://blog.youkuaiyun.com/hzoi_ztx/article/details/54898323

此时求最大比率的式子与01规划的式子有所不同(总算式加个负号)。

核心: 取定一个 r 值以后,带入最短路的新的dis[]更新公式,再判断是否存在至少一个负环(找出一个负环即可),存在负环和不存在负环两种情况指示了 r 应如何取下一个值,直到到达指定精度。


例题:Sightseeing Cows

#include<bits/stdc++.h>
#define ll long long
#define lf double
#define IOS std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define DEBUG cout<<",here\n";
#define Rep(i,l,r) for(int i=(l);i<=(r);i++)
#define rep(i,l,r) for(int i=(l);i< (r);i++)
#define Rev(i,r,l) for(int i=(r);i>=(l);i--)
#define rev(i,r,l) for(int i=(r);i> (l);i--)
#define MAXN 1005
#define INF 1e16
using namespace std;

inline ll quickPow(ll a,ll b,ll m){ll ans=1;while(b){if(b&1)ans=(a*ans)%m;a=(a*a)%m;b>>=1;}return ans;}

int f[MAXN];
struct SPFA//魔改版SPFA,dis[]更新与传统最短路不同
{
    struct To
    {
        int id;
        double v;
    };
    vector<To>node[MAXN];
    int inq[MAXN],inq_cnt[MAXN];
    double dis[MAXN];

    void init(int n){
        for(int i=1;i<=n;i++){dis[i]=INF;inq[i]=0;inq_cnt[i]=0;}
    }
    void add(int x,int y,double v){
        node[x].push_back({y,v});
    }
    int spfa(int n,int s,double m){//(int n,int start)
        queue<int>q;
        q.push(s);
        inq[s]=1;dis[s]=0;
        while(!q.empty()){
            int now=q.front();q.pop();
            inq[now]=0;
            if(inq_cnt[now]>=n){return 0;}//找不出最短路,有负环
            for(auto& i:node[now]){
                if(dis[now]+m*i.v-f[now]<dis[i.id]){
                    dis[i.id]=dis[now]+m*i.v-f[now];
                    if(!inq[i.id]){
                        q.push(i.id);inq[i.id]=1;
                        inq_cnt[i.id]++;
                    }
                }
            }
        }
        return 1;//能找到最短路
    }
};

SPFA spfa;
int n,m;
const double eps=1e-6;

int main()
{
    cin>>n>>m;
    spfa.init(n);
    Rep(i,1,n){cin>>f[i];}
    Rep(i,1,m){
        int x,y;double v;cin>>x>>y>>v;
        spfa.add(x,y,v);
    }
    double l=0,r=1000000.0;//不同的问题应该取不同的初始值
    while(r-l>eps){
        double M=(l+r)/2;
        spfa.init(n);
        int jug=0;
        Rep(i,1,n){
            if(spfa.inq_cnt[i]==0){
                if(spfa.spfa(n,i,M)==0)jug=1;
            }
        }
        if(jug) l=M;
        else r=M;
    }
    printf("%.2lf\n",r);

    return 0;
}

参考:
最优比率环
[POJ3621] Sightseeing Cows

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值