361. 观光奶牛

361. 观光奶牛

题意:

给一个带点权和边权的有向图,求图中一个 Σ点权/Σ边权 最大的环。

题解:

01分数规划裸题
可以拿来练练手

代码:

#include<bits/stdc++.h>
#define MAXN 2005 
#define inf int(1e9)
#define eps (1e-4)
using namespace std;
int N,M,s,t;

struct edge{
    
    
    int v,w;
    edge(int v=0, int w=0):v(v),w(w){
    
    };
};
vector<edge> adj[MAXN];

int f[MAXN], cnt[MAXN];
double d[MAXN];
bool inq[MAXN];

bool spfa(int s, double mid){
    
    
    queue<int> q;
    d[s] = 0; q.push(s); inq[s] = 1;

    int u,v;
    double w;
    while(!q.empty()){
    
     
        u = q.front(); q.pop(); inq[u] = 0;

        for(int i=0;i<adj[u].size();i++){
    
    
            v = adj[u][i].v; w = mid*adj[u][i].w - f[u];
            if(d[u] + w < d[v]){
    
    
                d[v] = d[u] + w;
                cnt[v] = cnt[u] + 1;
                if(cnt[v] >= N) return 1;//出现负环

                if(inq[v]==0){
    
    
                    q.push(v); inq[v] = 1;
                }   
            }
        }
    }   
    return 0;
}

bool chk(double mid){
    
    
    for(int i=1;i<=N;i++) d[i] = inf;
    memset(cnt, 0, sizeof(cnt));
    memset(inq,0,sizeof(inq));

    for(int i=1;i<=N;i++){
    
    
        if(d[i]==inf){
    
    
            if(spfa(i, mid)) return 1;
        }
    }
    return 0;
}

int main(){
    
    

    scanf("%d%d", &N, &M);
    for(int i=1;i<=N;i++){
    
    
        scanf("%d", &f[i]);
    }

    int u,v,w;
    for(int i=1;i<=M;i++){
    
      
        scanf("%d%d%d", &u, &v, &w);
        adj[u].push_back(edge(v,w));
    }

    double l = 0, r = 1e6, mid;
    double ans;
    while(r-l > eps){
    
    
        mid = (l+r)/2;
        if(chk(mid)) l = mid;
        else r = mid;
    }

    printf("%.2f\n", l);

    return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_35975367/article/details/115188821
今日推荐