洛谷 2868 观光奶牛Sightseeing Cows

给一个有向图,奶牛每次从图中任意一个点出发回到该点(至少经过两个点)。问sigma(点权)/sigma(边权)的最大值可以是多少。

首先从起点出发回到起点所经过的路程肯定是一个环。设最大值为ans。那么sigma(点权)/sigma(边权)=ans。

稍微化简上式子可以得到sigma(边权)*ans-sigma(点权)=0。二分答案,如果值小于答案那么以edge[i]*mid-v[i]为边的图必定存在负环。

那么只需要把是否存在负环作为二分判断条件即可。负环可以用dfs(O(nlogn)?)或者bfs(复杂度O(ke),k最大可能为n)两种方式得到。

 

 

bfs:

#include <bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
#define mem1(x) memset(x,-1,sizeof(x))
using namespace std;
typedef double db;
const int M = 1e3+7;
const int ME = 5e3+7;
const db eps = 1e-5;
int n,m,cnt,head[M],vis[M],num[M];
db val[M],dis[M],mid;
struct edge
{
    int v,next;
    db w;
}e[ME];
void add(int u,int v,db w){
    e[++cnt].v=v;e[cnt].w=w;e[cnt].next=head[u];
    head[u]=cnt;
}
void init(){
    cnt=0;mem1(head);
}

int checkspfa(){
    queue<int> q;
    for(int i=1;i<=n;i++){//初始距离都为0可以优化过滤掉距离大于0的路径
        dis[i]=0;vis[i]=num[i]=1;
        q.push(i);
    }
    while(!q.empty()){
        int u=q.front();q.pop();
        vis[u]=0;

        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].v;

            if(dis[v]>dis[u]+e[i].w*mid-val[v]){//更新条件
                dis[v]=dis[u]+e[i].w*mid-val[v];
                if(!vis[v]){
                    q.push(v);vis[v]=1;
                    if(++num[v]>=n){//如果一个点被其他点更新n次就存在负环
                        return 1;
                    }
                }
            }

        }

    }
    return 0;
}
int main(){
    init();
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%lf",&val[i]);
    for(int i=1;i<=m;i++){
        int from,to;db v;
        scanf("%d%d%lf",&from,&to,&v);
        add(from,to,v);
    }
    db l=1,r=1e4;
    while(r-l>eps){
        mid=(l+r)/2;
        if(checkspfa()) l=mid;
        else r=mid;
        //cout<<l<<endl;
    }
    printf("%.2f\n",l);
    return 0;
}
View Code

 

 

dfs:

#include <bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
#define mem1(x) memset(x,-1,sizeof(x))
using namespace std;
typedef double db;
const db eps = 1e-5;
const int ME = 5e3+7;
const int M = 1e3+7;
int n,m,cnt,head[M],vis[M];
db dis[M],val[M],mid;
struct edge
{
    int v,next;db w;
}e[ME];
void init(){
    cnt=0;mem1(head);
    mem(vis);mem(dis);//vis和dis必须初始化为0
}
void add(int u,int v,db w){
    e[++cnt].v=v;e[cnt].w=w;e[cnt].next=head[u];
    head[u]=cnt;
}
int spfa(int u){
    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].w*mid-val[v]){
            dis[v]=dis[u]+e[i].w*mid-val[v];
            if(vis[v]||spfa(v)){//该节点可以更新而且已经在栈里就有负环
                vis[u]=0;
                return 1;
            }
        }

    }
    vis[u]=0;
    return 0;
}
int check(){
    for(int i=1;i<=n;i++)//每个节点进行一次spfa
        if(spfa(i)) return 1;
    return 0;
}
int main(){
    init();
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%lf",&val[i]);
    for(int i=1;i<=m;i++){
        int from,to;db v;
        scanf("%d%d%lf",&from,&to,&v);
        add(from,to,v);
    }
    db l=1,r=1e4;
    while(r-l>eps){
        mid=(l+r)/2;
        if(check()) l=mid;
        else r=mid;
    }
    printf("%.2f\n",l);
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/LMissher/p/9562649.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值