01分数规划,SPFA——POJ3621

Posted helman

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了01分数规划,SPFA——POJ3621相关的知识,希望对你有一定的参考价值。

题目链接

题目含义

有一个有向图,每个点都有点权,每条边也都有边权

然后有头牛要从任一点出发,经过至少两个点后回到原点,即走一个环

问经过的sigma点权/sigma边权最大是多少

题目分析

最开始没想出来,看了网上说用SPFA判负环也有点不明白

因为不是说每个点的点权只得到一次吗,SPFA是怎么处理这点的?

然后想到,这是因为我在考虑排除原路返回的情况

因为原路返回没得到点权,反而增加了边权肯定是不划算的

但是SPFA判的负环根本不会原路返回啊!!!如果原路返回了,那还是环吗,那就是重叠边了呀

所以是我多虑了

——————————————————————

若sigmaPi/sigmaWi取得最大,那么任意一个答案ans必定<=sigmaPi/sigmaWi

转换一下就是 sigmaPi-sigmaWi*ans>=0  =>   sigma(  Pi-ans*Wi )>=0

然后就是二分,如果ans满足这个式子,low=mid,否则high=mid

但是这个sigma(Pi-ans*Wi)怎么求呢

只能想到用SPFA,如果有负环就说明从某一起点走一圈回到这个起点时sigma边权<0

所以将边权换成我们的Pi-ans*Wi就可以做了

题目代码

初始化手写就能过,memset就会wa,不知道为什么......

玄学memset

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
const int maxm=5007;
const int maxn=1007;
const double eps=1e-7;
struct edge
    int to,next,dis;
e[maxm];
int head[maxm],tot;
void add(int u,int v,int w)
    e[tot].dis=w;
    e[tot].to=v;
    e[tot].next=head[u];
    head[u]=tot++;

int f[maxn],n,m,a,b,c;
bool SPFA(double x)
    double dis[maxn];
    bool vis[maxn];
    int num[maxn];
    for(int i=1;i<=n;i++)
        dis[i]=1e100;
        vis[i]=false;
        num[i]=0;
    
//    memset(dis,1e100,sizeof(dis));
//    memset(vis,false,sizeof(vis));
//    memset(num,0,sizeof(num));
    queue<int>q;
    q.push(1);
    dis[1]=0;
    vis[1]=true;
    num[1]++;
    while(!q.empty())
        int u=q.front();q.pop();
        vis[u]=false;
        for(int i=head[u];i!=-1;i=e[i].next)
            int v=e[i].to;
            if(dis[v]>dis[u]+x*e[i].dis-f[v])
                dis[v]=dis[u]+x*e[i].dis-f[v];
                if(!vis[v])
                    vis[v]=true;
                    q.push(v);
                    num[v]++;
                    if(num[v]>n)return true;
                
            
        
    
    return false;

int main()
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&f[i]);
    memset(head,-1,sizeof(head));
    for(int i=1;i<=m;i++)
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
    
    double l=0.0,r=10000,mid;
    while(r-l>eps)
        mid=(l+r)/2;
        if(SPFA(mid))l=mid;
        else r=mid;
    
    printf("%.2f\n",mid);
    return 0;

 

以上是关于01分数规划,SPFA——POJ3621的主要内容,如果未能解决你的问题,请参考以下文章

01分数规划,SPFA——POJ3621

POJ 3621 Sightseeing Cows (bellman-Ford + 01分数规划)

POJ 3621 Sightseeing Cows | 01分数规划

POJ 3621 Sightseeing Cows 01分数规划,最优比例环的问题

POJ3621Sightseeing Cows 分数规划

[做题手记·分数规划]POJ 3621-Sightseeing Cows