做题记录整理二分5 P3199 [HNOI2009] 最小圈(2022/9/15)
题目看着花里胡哨的,其实本质上就是一个有向图,希望你找一个平均值最小的环
我们选择二分平均值,然后对于每条边都减去这个值(不用真的减),然后是spfa找负环,如果找到负环说明二分大了,再往小的二分就可以了
有一个需要注意的点就是这题的l需要取到-inf,因为答案可能是负数
#include<bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i<=b;i++)
#define ll long long
#define mp(a,b) make_pair(a,b)
using namespace std;
int n,m;
int a[500005];
struct node {
int v,nex;
double w;
} e[200010];
int hd[500005],cnt;
int vis[500005],kg;
double d[500005];
void ru(int u,int v,double w) {
e[++cnt].nex=hd[u];
e[cnt].v=v;
e[cnt].w=w;
hd[u]=cnt;
}
void check(int u,double x) {
vis[u]=1;
for(int i=hd[u]; i; i=e[i].nex) {
int v=e[i].v;
double w=e[i].w;
if(d[v]>d[u]+w-x) {
if(vis[v]||kg) {
kg=1;
break;
}
d[v]=d[u]+w-x;
check(v,x);
}
}
vis[u]=0;
}
int main() {
double w;
int u,v;
cin>>n>>m;
for1(i,1,m) {
scanf("%d%d",&u,&v);
scanf("%lf",&w);
ru(u,v,w);
}
double ans;
double l=-1e8,r=1e8,mid;
while(r-l>1e-10) {
mid=(l+r)/2;
for1(i,1,n) d[i]=0;
kg=0;
for1(i,1,n) vis[i]=0;
for(int i=1; i<=n; ++i) {
check(i,mid);
if(kg) break;
}
if(kg)r=mid;
else l=mid,ans=l;
}
printf("%.8f",ans);
return 0;
}

浙公网安备 33010602011771号