zoukankan      html  css  js  c++  java
  • 01 分数规划

    P2868 Sightseeing Cows G

    给出一个 (n) 个点 (m) 条的有点权与边权的有向图,求一个环使得环上的点权和除以边权和最大。

    最优比率环问题,显然01分数规划

    环上第(i)个点点权为(a_i),第(i)条边的边权为(b_i)

    [frac{sum_{i=1}^nF_i}{sum_{i=1}^mT_i}=ans\ 对于01分数规划,考虑二分.二分可以将最优化问题转化为判定问题.如果二分出来mid为L,则问题转化为是否存在\ frac{sum F_i}{sum T_i}>L~~~分母乘过去(T_i>0)\ sum(F_i-L*T_i)>0~~左式乘-1~~~sum(L*T_i-F_i)<0\ 问题转化为求负环,对于入点为u_i,出点为v_i的边e_i,把边权看做mid*T[e_i]-F[u_i],判负环\ 有负环则L=mid,否则R=mid ]

    #include<cstdio>
    #include<queue>
    #include<iostream>
    #define maxm 5005
    #define maxn 1002
    using namespace std;
    inline int read() {
        int x = 0,f = 1; char s = getchar();
        while(s < '0' || s > '9') {if(s == '-') f = -1;s = getchar();}
        while(s >= '0' && s <= '9') {x = x * 10 + s - '0';s = getchar();}
        return f * x;
    }
    int l,p,head[maxn],tot = 0,vis[maxn],num[maxn],a[maxn];
    double d[maxn];
    struct edge{
    	int to,next,dis;
    }e[maxm];
    inline void add(int u,int v,int w){
    	e[++tot].to = v;
    	e[tot].next = head[u];
    	e[tot].dis = w;
    	head[u] = tot;
    }
    int check(double x){//找负环 
    	queue<int> q;
    	for(int i = 1;i <= l;i++){
    		q.push(i);
    		d[i] = 0;vis[i] = num[i] = 1;
    	}
    	while(!q.empty()){
    		int u = q.front();
    		q.pop();vis[u] = 0;
    		for(int i = head[u];i;i = e[i].next){
    			int v = e[i].to;
    			double dis = (double)e[i].dis;
    			if(d[v] > d[u] + x * dis - (double)a[u])//边权为mid*Tim[e_i]-Fun[u_i]
                {
                    d[v] = d[u] + x * dis - (double)a[u];
                    if(!vis[v])
                    {
                        q.push(v); vis[v]=1;
                        if(++num[v] >= l) return 1;
                    }
                }
    		} 
    	}
    	return 0;
    }
    int main(){
     l=read();p=read();
        for(int i=1;i<=l;++i)a[i]=read();
        for(int i=1;i<=p;++i)
        {
            int u=read(),v=read(),dis=read();
            add(u,v,dis);
        }
        double L=0,R=5001,mid;
        while(R-L>1e-4)
        {
            mid=(L+R)/2;
            if(check(mid))L=mid;
            else R=mid;
        }
        printf("%.2lf",L);
        return 0;
    }
    

    P4377 [USACO18OPEN]Talent Show G

    乍眼一看,这题好裸,裸题就意味着神题(裸体就意味着身体)

    [1.分数规划\ ans=frac{sum t_i}{sum w_i}(sum w_ige W)\ frac{sum t_i}{sum w_i}ge mid \ 所以要求sum (t_i-mid*w_i)ge0,令c_i=t_i-mid*w_i\ 2.~~01背包,做个大小为W的背包,重量大于dp[w]的,都记在dp[w]上,最后只要看dp[W]是否>0 ]

    #include<cstdio>
    #include<iostream>
    #define INF 0x3f3f3f3f
    #define maxn 251
    #define maxm 1005
    using namespace std;
    int n, W;
    int w[maxn],t[maxn];
    double dp[maxm],c[maxn];
    inline int max(int a,int b){return a > b ? a : b;}
    inline int check(double mid){
    	for(int i = 1;i <= n;i++) c[i] = (double)t[i] - mid * w[i];
    	for(int i = 1;i <= W;i++)	dp[i] = -INF;
    	for(int i = 1;i <= n;i++)
    		for(int j = W;j >= 0;j--){
    			if(j + w[i] >= W) dp[W]=max(dp[W], dp[j] + c[i]);
    			else dp[j+w[i]]=max(dp[j+w[i]],dp[j]+c[i]);
    		}
    	return dp[W]>=0;
    }
    int main(){
    	scanf("%d%d",&n,&W);
    	double l=0,r=0;
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d%d",&w[i],&t[i]);
    		r+=t[i];
    	}
    	while(l+1e-5<=r)
    	{
    		double mid=(l+r)/2;
    		if(check(mid))
    		{
    			l=mid;	
    		}
    		else 
    			r=mid;
    	}
    	int ans = (int)(l*1000);
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    respons——文件下载
    李珊珊(为奥运冠军名字作诗)
    林跃/火亮(为奥运冠军名字作诗)
    张湘祥(为奥运冠军名字作诗)
    何可欣(为奥运冠军名字作诗)
    李小鹏(为奥运冠军名字作诗)
    王鑫(为奥运冠军名字作诗)
    杨伊琳(为奥运冠军名字作诗)
    江钰源(为奥运冠军名字作诗)
    黄旭(为奥运冠军名字作诗)
  • 原文地址:https://www.cnblogs.com/shikeyu/p/13368165.html
Copyright © 2011-2022 走看看