01规划 最优比例生成树&最优比例环

可能见得最多的就是最优比例生成树,常用的解决方案就是二分枚举答案。
最优比例生成树一般求解最大值,如果求最小值那么转换成最大值的倒数即可。求最大值的检测条件是使得式子>=0。

最优比例环,一般求解最小值,如果求最大值那么转换成求最小值的倒数。
求最小值的检测条件是图存在负环。

bzoj 1486 最优比例环
在这道题里如果用spfa或许会tle。可用dfs式的spfa判断负环,沿着边权和减少的方向深搜,如果搜到之前访问过的,那么就存在负环。这里是回溯深搜~

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include<string.h>
#include <fstream>
#include <iostream>
#include <algorithm>
using namespace std;
#define exp 1e-8
#define INF 0x3f3f3f3f
#define ll __int64    //%I64d
#define mm(a,b) memset(a,b,sizeof(a));
#define for1(a,b) for(int a=1;a<=b;a++)//1---(b)
#define for0(a,b) for(int a=0;a<=b;a++)//0---(b)
void bug(string st="bug")
{cout<<st<<endl;}
template<typename __ll>
inline void READ(__ll &m){
    __ll x=0,f=1;char ch=getchar();
    while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    m=x*f;
}
template<typename __ll>
inline void read(__ll &m){READ(m);}
template<typename __ll>
inline void read(__ll &m,__ll &a){READ(m);READ(a);}
template<typename __ll>
inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);}
const int cnt_edge=100000;  //修改啊
const int cnt_v=100000;
int head[cnt_v],cnt;
struct EDGE
{
    int u,v,next;
    double cost;
}edge[cnt_edge];
int n,m;
int dat[10010][3];
double cost[10010];
bool flag;
double dist[4000];
bool vis[4000];
void addedge(int u,int v,double cost=0)
{
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].cost=cost;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void init()  初始化啊
{
    flag=0;
    cnt=0;
    memset(head,-1,sizeof(head));
}
void dfs(int u)
{
    if(flag)return ;
    vis[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(dist[v]>dist[u]+edge[i].cost)
        {
            if(vis[v])
            {
                flag=1;
                return ;
            }
            dist[v]=dist[u]+edge[i].cost;
            dfs(v);
        }
    }
    vis[u]=0;
}
bool check(double mid)
{
    init();
    for1(i,m)addedge(dat[i][1],dat[i][2],cost[i]-mid);
    mm(dist,0);  //判断负环  这样子初始化就可以了
    mm(vis,0);
    for1(i,n)
    {
        dfs(i);
        if(flag)return 1;
    }
    return 0;
}
int main()
{
    read(n,m);
    for1(i,m)read(dat[i][1],dat[i][2]),scanf("%lf",&cost[i]);
    double l=-1000000000,r=1000000000;
    while(r-l>=exp)
    {
        double mid=(l+r)/2;
        if(check(mid))r=mid;
        else l=mid;
    }
    printf("%.8lf\n",r);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值