#结论#洛谷 3199 [HNOI2009]最小圈
题目
求有向图最小平均权值回路。
\(n\leq 3*10^3,m\leq 10^4\)
分析
设 \(f_k(x)\) 表示从点 \(x\) 出发恰好走 \(k\) 条边的最短路,
那么答案就是 \(\min_{x=1}^n\max_{k=0}^{n-1}\frac{f_n(x)-f_k(x)}{n-k}\)
所以直接 \(O(nm)\) 就可以了,证明见_rqy dalao的博客
0/1分数规划的方法理论应该会T这里就不写了,不过只要任意点都可以作为起点那么初始值都为0就可以了
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
const int N=3411; typedef double db;
int as[N],n,m; db f[N][N],ans=1e15;
struct node{int y; db w; int next;}e[N*3];
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline void Max(db &x,db y){x=x>y?x:y;}
inline void Min(db &x,db y){x=x<y?x:y;} 
signed main(){
    n=iut(); m=iut();
    for (rr int i=1;i<=m;++i){
        rr int x=iut(),y=iut();
        rr db w; scanf("%lf",&w);
        e[i]=(node){y,w,as[x]},as[x]=i;
    }
	for (rr int i=1;i<=n;++i){
		for (rr int x=1;x<=n;++x) f[i][x]=1e15;
		for (rr int x=1;x<=n;++x)
		if (f[i-1][x]!=1e15)
		   for (rr int j=as[x];j;j=e[j].next)
		       Min(f[i][e[j].y],f[i-1][x]+e[j].w);
	}
	for (rr int i=1;i<=n;++i){
		rr db now=-1e15;
	    for (rr int j=0;j<n;++j)
	        Max(now,(f[n][i]-f[j][i])/(n-j));
		Min(ans,now); 
	}
	return !printf("%.8lf",ans);
}
0/1分数规划代码
#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
const int N=3011; int as[N],n,m; bool v[N]; double dis[N];
struct node{int y; double w; int next;}e[N*5];
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline bool dfs(int x,double mid){
    v[x]=1;
    for (rr int i=as[x];i;i=e[i].next)
    if (dis[e[i].y]>dis[x]+e[i].w-mid){
        if (v[e[i].y]) return 0;
        dis[e[i].y]=dis[x]+e[i].w-mid;
        if (!dfs(e[i].y,mid)) return 0;
    }
    v[x]=0;
    return 1;
}
signed main(){
    n=iut(); m=iut();
    for (rr int i=1;i<=m;++i){
        rr int x=iut(),y=iut();
        rr double w; scanf("%lf",&w);
        e[i]=(node){y,w,as[x]},as[x]=i;
    }
    for (rr int i=1;i<=n;++i)
        e[i+m]=(node){i,0,as[n+1]},as[n+1]=m+i;
    rr double l=-5000,r=5000;
    while (l+1e-9<r){
        rr double mid=(l+r)/2;
        for (rr int i=1;i<=n+1;++i) dis[i]=v[i]=0;
        if (dfs(n+1,mid)) l=mid;
		    else r=mid;
    }
    return !printf("%.8lf",l);
}

                
            
        
浙公网安备 33010602011771号