*题解:P3199 [HNOI2009] 最小圈
解析
考虑我刚学的分数规划。二分答案 \(x\),问题转化为判定是否有
\[\frac{\sum_{i=1}^{k}w_{c_i,c_{i + 1}}}{k} \le x
\]
变形一下:
\[\sum_{i=1}^{k}(w_{c_i,c_{i + 1}} - x)\le 0
\]
将边权设为 \(w_{c_i,c_{i + 1}} - x\),要判定的就是是否有非正环,SPFA 即可。
时间复杂度 \(O(nm\log w)\)。
代码
/*
*/
#include <bits/stdc++.h>
#define eps 0.0000000001
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 23000 + 5,M = 1000 + 5,P = 2000000,mod = 45989;
int head[N],to[N],nxt[N],e;
double val[N];
double dis[N];
int cnt[N],inq[N];
int n,m;
void add(int u,int v,double w){
e++;
val[e] = w;
to[e] = v;
nxt[e] = head[u];
head[u] = e;
}
bool chk(double mid){
queue<int> q;
for(int i=1;i<=n;i++){
dis[i] = 0;
inq[i] = true;
cnt[i] = 0;
q.push(i);
}
while(!q.empty()){
int u = q.front();
q.pop();
inq[u] = false;
for(int i=head[u];i;i = nxt[i]){
int v = to[i];
double w = val[i];
if(dis[v] >= dis[u] + w - mid){
dis[v] = dis[u] + w - mid;
if(!inq[v]){
inq[v] = true;
cnt[v]++;
if(cnt[v] >= n + 5){
return true;
}
q.push(v);
}
}
}
}
return false;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
double w;
cin>>u>>v>>w;
add(u,v,w);
}
double l = -1e7,r = 1e7;
while(r - l > eps){
double mid = (l + r) / 2;
if(chk(mid)) r = mid;
else l = mid;
}
cout<<fixed<<setprecision(8)<<l;
return 0;
}

浙公网安备 33010602011771号