• bzoj1486 [HNOI2009]最小圈


    很容易看出0/1分数规划

    但是……好久没写我都忘了怎么做

    二分+spfa判负环啦

    01分数规划是这样的:有一堆物品,每个都有价值a[i],和代价b[i]。要使所有物品中取到的Σa[i]/Σb[i]取最值。

    设k为一个可能的取值,那么令d[i]=a[i]-k*b[i]。这题中a[i]就是第i条边的权,b[i]都是1

    若d[i]>0,则显然k的值还可以再增加。

    这个是最优比率环

    二分一个k,然后重新建图,权值就是d[i]。然后枚举每个点跑spfa判负环。如果有负环就不行,否则更新答案

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<deque>
    #include<set>
    #include<map>
    #include<ctime>
    #define LL long long
    #define inf 0x7ffffff
    #define pa pair<int,int>
    #define pi 3.1415926535897932384626433832795028841971
    #define eps 1e-10
    using namespace std;
    inline LL read()
    {
        LL x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void write(LL a)
    {
        if (a<0){printf("-");a=-a;}
        if (a>=10)write(a/10);
        putchar(a%10+'0');
    }
    inline void writeln(LL a){write(a);printf("
    ");}
    struct edge{
    	int to,next;
    	double v,v0;
    }e[100010];
    int n,m,cnt;
    bool fnd,mrk[100010];
    int head[100010];
    double dist[100010];
    double l=-1000000000.0,r=1000000000.0,ans=0.0;
    inline void ins(int u,int v,double w)
    {
    	e[++cnt].to=v;
    	e[cnt].v0=w;
    	e[cnt].next=head[u];
    	head[u]=cnt;
    }
    inline void spfa(int x)
    {
    	mrk[x]=1;
    	for (int i=head[x];i;i=e[i].next)
    		if (dist[e[i].to]>dist[x]+e[i].v)
    		{
    			if (mrk[e[i].to]){fnd=1;return;}
    			dist[e[i].to]=dist[x]+e[i].v;
    			spfa(e[i].to);
    			if (fnd)return;
    		}
    	mrk[x]=0;
    }
    inline bool jud()
    {
    	fnd=0;
    	memset(mrk,0,sizeof(mrk));
    	memset(dist,0,sizeof(dist));
    	for (int i=1;i<=n;i++)
    	{
    		spfa(i);
    		if (fnd)return 0;
    	}
    	return 1;
    }
    int main()
    {
    	n=read();m=read();
    	for(int i=1;i<=m;i++)
    	{
    		int x=read(),y=read();
    		double z;scanf("%lf",&z);
    		ins(x,y,z);
    	}
    	while (r-l>=eps)
    	{
    		double mid=(l+r)/2;
    		for (int i=1;i<=n;i++)
    			for (int j=head[i];j;j=e[j].next)
    				e[j].v=(e[j].v0-mid);
    		if (jud()){ans=mid;l=mid;}
    		else r=mid;
    	}
    	printf("%.8lf
    ",ans);
    }
    
    ——by zhber,转载请注明来源
  • 相关阅读:
    洛谷P1072 Hankson 的趣味题(题解)
    18.3.19晚听韩明睿大佬讲题收获
    题解+新技巧--一本通1282:最大子矩阵
    题解-洛谷P1303 A*B Problem(高精)
    Java重载和覆盖
    propagation属性的7个传播行为
    脏读、不可重复读、幻读
    RSA 数据加密和数字签名算法
    大型互联网站解决高并发的常见策略
    死锁和活锁
  • 原文地址:https://www.cnblogs.com/zhber/p/4180420.html
Copyright © 2020-2023  润新知