题目描述:
求最小平均权值环
题目分析:
很明显是个分数规划的题目
ans=(∑ki=1w[i])/k
a
n
s
=
(
∑
i
=
1
k
w
[
i
]
)
/
k
ans∗k=(∑ki=1w[i])
a
n
s
∗
k
=
(
∑
i
=
1
k
w
[
i
]
)
(∑ki=1w[i])−ans∗k=0
(
∑
i
=
1
k
w
[
i
]
)
−
a
n
s
∗
k
=
0
如果我们能够在图中找到一个负环,就说明ans可以继续缩小
使用实数二分即可
题目链接:
Ac 代码:
// luogu-judger-enable-o2
#include <cstdio>
#include <iostream>
#include <cstring>
const double eps=1e-10;
const int maxm=11000;
int head[maxm],to[maxm],net[maxm];
int cnt;
double cost[maxm],dis[maxm];
int n,m;
void addedge(int u,int v,double c)
{
cnt++;
to[cnt]=v,cost[cnt]=c,net[cnt]=head[u],head[u]=cnt;
}
bool vis[maxm];
bool dfs(int now,double x)
{
vis[now]=1;
for(int i=head[now];i;i=net[i])
if(dis[to[i]]>dis[now]+cost[i]-x)
{
dis[to[i]]=dis[now]+cost[i]-x;
if(vis[to[i]]) return 1;
else if(dfs(to[i],x)) return 1;
}
return vis[now]=0;
}
bool check(double mid)
{
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
if(dfs(i,mid)) return 1;
return 0;
}
int main()
{
double l=1e9,r=-1e9;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v;
double c;
scanf("%d%d%lf",&u,&v,&c);
addedge(u,v,c);
l=std::min(l,c);
r=std::max(r,c);
}
while(r-l>eps)
{
double mid=(l+r)/2.0;
if(check(mid)) r=mid;
else l=mid;
}
return printf("%.8lf\n",l)*0;
}