[HNOI2009] 最小圈

[HNOI2009] 最小圈

题目描述

考虑带权有向图 G = ( V , E ) G=(V,E) G=(V,E) 以及 w : E → R w:E\rightarrow \R w:ER,每条边 e = ( i , j ) e=(i,j) e=(i,j) i ≠ j i\neq j i=j i , j ∈ V i, j\in V i,jV)的权值定义为 w i , j w_{i,j} wi,j。设 n = ∣ V ∣ n=|V| n=V

c = ( c 1 , c 2 , ⋯   , c k ) c=(c_1,c_2,\cdots,c_k) c=(c1,c2,,ck) c i ∈ V c_i\in V ciV)是 G G G 中的一个圈当且仅当 ( c i , c i + 1 ) (c_i,c_{i+1}) (ci,ci+1) 1 ≤ i < k 1\le i<k 1i<k)和 ( c k , c 1 ) (c_k,c_1) (ck,c1) 都在 E E E 中。称 k k k 为圈 c c c 的长度,同时记 c k + 1 = c 1 c_{k+1}=c_1 ck+1=c1,并定义圈 c = ( c 1 , c 2 , ⋯   , c k ) c=(c_1,c_2,\cdots,c_k) c=(c1,c2,,ck) 的平均值为
μ ( c ) = 1 k ∑ i = 1 k w c i , c i + 1 \mu(c)= \frac 1 k \sum\limits_{i=1}^{k} w_{c_i,c_{i+1}} μ(c)=k1i=1kwci,ci+1
c c c 上所有边的权值的平均值。设 μ ′ ( G ) = min ⁡ c μ ( c ) \mu'(G)=\min_c\mu(c) μ(G)=mincμ(c) G G G 中所有圈 c c c 的平均值的最小值。

给定图 G = ( V , E ) G=(V,E) G=(V,E) 以及 w : E → R w:E\rightarrow \R w:ER,求出 G G G 中所有圈 c c c 的平均值的最小值 μ ′ ( G ) \mu'(G) μ(G)

输入格式

第一行两个正整数,分别为 n n n m m m,并用一个空格隔开。其中 n = ∣ V ∣ n=|V| n=V m = ∣ E ∣ m=|E| m=E 分别表示图中有 n n n 个点 和 m m m 条边。

接下来 m m m 行,每行三个数 i , j , w i , j i,j,w_{i,j} i,j,wi,j,表示有一条边 ( i , j ) (i,j) (i,j) 且该边的权值为 w i , j w_{i,j} wi,j,注意边权可以是实数。输入数据保证图 G = ( V , E ) G=(V,E) G=(V,E) 连通,存在圈且有一个点能到达其他所有点。

输出格式

一个实数 μ ′ ( G ) \mu'(G) μ(G),要求精确到小数点后 8 8 8 位。

样例 #1

样例输入 #1

4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3

样例输出 #1

3.66666667

样例 #2

样例输入 #2

2 2
1 2 -2.9
2 1 -3.1

样例输出 #2

-3.00000000

提示

对于 100 % 100\% 100% 的数据, 2 ≤ n ≤ 3000 2\leq n\le 3000 2n3000 1 ≤ m ≤ 10000 1\leq m\le 10000 1m10000 ∣ w i , j ∣ ≤ 1 0 7 |w_{i,j}| \le 10^7 wi,j107 1 ≤ i , j ≤ n 1\leq i, j\leq n 1i,jn i ≠ j i\neq j i=j


提示:本题存在 O ( n m ) O(nm) O(nm) 的做法,但是 O ( n m log ⁡ n ) O(nm\log n) O(nmlogn) 的做法也可以通过。

题意

我们需要在一张有向图上找到一个"平均权值最小的一个圈"。

分析

我们观察圈的平均权值的定义
μ ( c ) = 1 k ∑ i = 1 k w c i , c i + 1 \mu(c)= \frac 1 k \sum\limits_{i=1}^{k} w_{c_i,c_{i+1}} μ(c)=k1i=1kwci,ci+1
处理一下
μ ( c ) = ∑ i = 1 n W i k \mu(c) = \sum_{i = 1}^{n} \frac{W_i}{k} μ(c)=i=1nkWi
这种形式的分式,常见的做法(我知道的做法 )就是分式规划了。
我们设:
∑ i = 1 k W i k ≤ X \sum_{i = 1}^{k} \frac{W_i}{k} \le X i=1kkWiX
处理一下
∑ i = 1 k ( W i − X ) ≤ 0 \sum_{i = 1}^{k} (W_i - X) \le 0 i=1k(WiX)0
意味着我们以 W i − X W_i - X WiX 为 权值建图,在图中如果找到了负环则说明上式成立。我们知道SPFA算法可以寻找负环(简单来说,如果一个点到起点的距离被重复更新,说明图中存在负环)。

时间复杂度: 我们需要跑整个图 N M N M NM的复杂度,分数规划二分复杂度 l o g ( W ∗ W ) log(W*W) log(WW), 总复杂度:
O ( N M l o g ( W ∗ W ) ) O(NMlog(W*W)) O(NMlog(WW))

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
//#define int long long
#define double long double
#define ios ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
const int N = 1e5+5;
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
typedef pair<int, double > PID;
int n, m, vis[N];
double dis[N];
vector<PID> e[N];

bool spfa(int u, double x){
    vis[u] = 1;
    for(auto [v, w] : e[u]){
        if(dis[v] > dis[u] + w - x){
            dis[v] = dis[u] + w - x;
            if(vis[v] || spfa(v, x)) return 1;
        }
    }
    vis[u] = 0;
    return 0;
}

bool check(double x){
    memset(vis, 0, sizeof(vis));
    for(int i = 1; i <= n; i++) dis[i] = INF;
    for(int i = 1; i <= n; i++){
        if(spfa(i, x)) return 1;
    }
    return 0;
}

void solve(){
    cin >> n >> m;
    int u, v;
    double w;
    for(int i = 1; i <= m; i++){
        cin >> u >> v >> w;
        e[u].push_back({v, w});
    }
    double l = -1e7, r = 1e7; 
    while(r - l > eps){
        double mid = (l + r)/2;
        if(check(mid)) r = mid;
        else l = mid;
    }
    //cout << fixed << setprecision(10) << l <<" " << r << endl;
    cout << fixed << setprecision(8) << (r) << endl;
}

signed main(){
    ios; int _;
    _ = 1; //cin >> _;
    while(_--){
        solve();
    }
    return 0;
}
  • 10
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值