【题意】:
【思路】:
像这种求最大、最小平均值的题目,我们可以考虑二分
像本题,我们可以二分答案 m i d mid mid,然后把所有边的长度减去 m i d mid mid,然后我们对于每个点,都跑一遍 S P F A SPFA SPFA判负环
若以某个点为起点成功找到负环,那么我们可以减小二分答案 m i d mid mid,否则我们只能减小二分答案 m i d mid mid
二分最后的答案为 l l l,至于精度,只需精确到 1 0 − 10 10^{-10} 10−10,即 1 e − 10 1e-10 1e−10即可通过本题
理论最坏时间复杂度比较高,但可以通过本题,而且也只用了 105 m s 105ms 105ms,因为 S P F A SPFA SPFA的理论最优时间复杂度为 O ( m ) O(m) O(m)
其实,判负环有一种很好的方法,但很复杂,这里就不讲了
【如何判断负环】:
bool spfa(int u){
vis[u]=true;int i;
for(i=h[u];i;i=e[i].next){
register int to=e[i].to;
if (d[to]>d[u]+e[i].len){
d[to]=d[u]+e[i].len;
if (vis[to]) return true;
else if (spfa(to,mid)) return true;
}
}
vis[u]=false;
return false;
}
//spfa(u)==true表示以u为起点有负环
//spfa(u)==false表示以u为起点无负环
//d数组初始化为0,vis数组初始化为false
【如何实数二分】:
l=minn;r=maxn;//l,r的初始值
while (l+eps<r){
mid=(l+r)/2;
if (check(mid)){
// ans=mid;
r=mid;//这里随题目要求不同而不同
}
else l=mid;//同上
}
【代码】:
//By HPXXZYY,Accepted,100 points,105ms,1.13MB,1.25KB
#include
using namespace std;
const int N=10100,M=3010;
struct node{
int next,to;
double len;
}e[N+M];int h[M],tot,n,m;
inline void add(int a,int b,double c){
e[++tot]=(node){h[a],b,c};h[a]=tot;
// e[++tot]=(node){h[b],a,c};h[b]=tot;//若为无向图,则加上此句
}
double d[M];bool vis[M];
const double eps=1e-10;//随题目要求不同而不同的精度,一般题目要求k位,就精确到k+2位即可
bool spfa(int u,double mid){
vis[u]=true;int i;
for(i=h[u];i;i=e[i].next){
register int to=e[i].to;
if (d[to]>d[u]+e[i].len-mid){
d[to]=d[u]+e[i].len-mid;
if (vis[to]) return true;
else if (spfa(to,mid)) return true;
}
}
vis[u]=false;
return false;
}
int from[N],to[N];double len[N];
inline bool check(double mid){
memset(d,0,sizeof(d));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
if (spfa(i,mid)) return true;
return false;
}
double l,r,mid,ans,minn,maxn;
int main(){
// freopen("t1.in","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%lf",&from[i],&to[i],&len[i]);
minn=1e20;maxn=-minn;
for(int i=1;i<=m;i++){
minn=min(minn,len[i]);
maxn=max(maxn,len[i]);
}
for(int i=1;i<=m;i++)
add(from[i],to[i],len[i]);
l=minn;r=maxn;
while (l+eps<r){
mid=(l+r)/2;
if (check(mid)){
// ans=mid;
r=mid;
}
else l=mid;
}
printf("%.8lf",l);
return 0;
}