Uva 11090 Going in Cycle!!(二分+最短路)

题意:求带权值的有向环的平均值的最小值

思路:二分最小值,如果存在更小的值,那么c1+c2+...+ck < k * mid,即(c1-mid)+(c2-mid)+...(ck-mid) < 0(存在负环),判断是否存在负环即可

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
const int maxn = 55;
const double INF = 1e9 + 10;
const double eps = 1e-5;
using namespace std;

struct P {
    int to;
    double cost;
    P(int t, double c) : to(t), cost(c) {}
};
double nec[maxn][maxn], up[maxn][maxn], d[maxn];
int vis[maxn], in[maxn];
int use[maxn];
int n, m, T, t = 1;
vector<P> G[maxn];

bool operator < (P a, P b) {
    return a.cost > b.cost;
}

void init() {
    for(int i = 0; i < maxn; i++)
        G[i].clear();
    for(int i = 0; i < maxn; i++) {
        for(int j = 0; j < maxn; j++)
            nec[i][j] = INF;
    }
    memset(in, 0, sizeof(in));
}

int topo() {
    stack<int> s;
    for(int i = 1; i <= n; i++) {
        if(!in[i]) s.push(i);
    }
    while(!s.empty()) {
        int p = s.top(); s.pop();
        for(int i = 0; i < G[p].size(); i++) {
            int u = G[p][i].to;
            in[u]--;
            if(!in[u]) s.push(u);
        }
    }
    for(int i = 1; i <= n; i++) {
        if(in[i]) return 1;
    }
    return 0;
}

int dijkstra(double mid, int st) {
    fill(d, d + maxn, INF);
    memset(vis, 0, sizeof(vis));
    for(int i = 0; i < maxn; i++) {
        for(int j = 0; j < maxn; j++) {
            up[i][j] = nec[i][j] - mid;
        }
    }
    priority_queue<P> q;
    use[st] = vis[st] = 1;
    d[st] = 0;
    q.push(P(st, 0));
    while(!q.empty()) {
        P p = q.top(); q.pop();
        int u = p.to;
        if(d[u] < p.cost) continue;
        for(int i = 0; i < G[u].size(); i++) {
            P g = G[u][i];
            use[g.to] = 1;
            if(d[g.to] > d[u] + up[u][g.to]) {
                d[g.to] = d[u] + up[u][g.to];
                vis[g.to]++;
                q.push(P(g.to, d[g.to]));
            }
            if(vis[g.to] > maxn) return 1;
        }
    }
    return 0;
}

double solve() {
    double l = 0, r = INF;
    while(l + eps <= r) {
        double mid = (l + r) / 2;
        memset(use, 0, sizeof(use));
        int sign = 0;
        for(int i = 1; i <= n; i++) {
            if(use[i] || !in[i]) continue;
            sign = dijkstra(mid, i);
            if(sign) break;
        }
        if(sign) r = mid - eps;
        else l = mid;
    }
    return r;
}

int main() {
    scanf("%d", &T);
    while(T--) {
        init();
        scanf("%d %d", &n, &m);
        while(m--) {
            int f, tt;
            double C;
            scanf("%d %d %lf", &f, &tt, &C);
            nec[f][tt] = min(nec[f][tt], C);
            G[f].push_back(P(tt, 0));
            in[tt]++;
        }
        int sign = topo();
        printf("Case #%d: ", t++);
        if(!sign) printf("No cycle found.\n");
        else printf("%.2f\n", solve());
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值