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

    分数规划

    ==建议先看资料照着推一下 知道怎么回事了以后忘了也会推...

    资料

    这样一类问题,给定两个数组,benifit[i]表示选取i的收益,cost[i]表示选取i的代价。如果选取i,定义x[i]=1否则x[i]=0。每一个物品只有选或者不选两种方案,求一个选择方案使得(R=sum(benifit[i]*x[i])/sum(cost[i]*x[i]))取得最值,即所有选择物品的总收益与总代价的比值最大或是最小

    我的笔记当然是在笔记本上鸭

    实战

    POJ2976Dropping tests 普通01分数规划

    题意:给出n个a和b,让选出n-k个使得((sum a[i])/(sum b[i]))最大
    普通分数规划 就是因为是实数要注意一些小细节

    二分
    #define ll long long
    #define Abs(x) ((x)<0?-(x):(x))
    #define Max(x,y) ((x)>(y)?(x):(y))
    #define Min(x,y) ((x)<(y)?(x):(y))
    const int N=1e5+5,M=5e5+5,INF=1e9+7,inf=0x3f3f3f3f;
    const double eps=1e-7;
    int n,k,a[N],b[N];
    double d[N];
    template void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    double check(double l){
    	double sum=0.0;
    	for(int i=1;i<=n;++i) d[i]=(double)a[i]-l*b[i];
    	sort(d+1,d+n+1);
    	for(int i=n-k+1;i<=n;++i) sum+=d[i];
    	return sum;
    }
    int main(){
    	freopen("bb.txt","r",stdin);
    	rd(n),rd(k);
    	double l=0.0,r=0.0,mid;
    	for(int i=1;i<=n;++i) rd(a[i]);
    	for(int i=1;i<=n;++i){
    		rd(b[i]);
    		r=Max(r,1.0*a[i]/b[i]);
    	}
    	while(r-l>=eps){
    		mid=(l+r)/2;
    		if(check(mid)>0) l=mid;
    		else r=mid;
    	}
    	printf("%.4lf
    ",l);
    	return 0;
    }
    
    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring> 
    using namespace std;
    #define ll long long
    #define Abs(x) ((x)<0?-(x):(x))
    const int N=1000+5,M=5e5+5,INF=1e9+7,inf=0x3f3f3f3f;
    const double eps=1e-7;
    int n,k;
    double a[N],b[N],d[N];
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    double check(double l){
    	double sum=0.0;
    	for(int i=1;i<=n;++i) d[i]=a[i]-l*b[i];
    	sort(d+1,d+n+1);
    	for(int i=k+1;i<=n;++i) sum+=d[i];
    	return sum;
    }
    
    int main(){
    	while(scanf("%d%d",&n,&k)!=EOF&&n+k){
    		double l=0.0,r=0.0,mid;
    		for(int i=1;i<=n;++i) scanf("%lf",&a[i]);
    		for(int i=1;i<=n;++i){
    			scanf("%lf",&b[i]);
    			if(a[i]/b[i]>r) r=a[i]/b[i];
    		}
    		while(r-l>eps){
    			mid=(l+r)/2;
    			if(check(mid)>0) l=mid;
    			else r=mid;
    		}
    		printf("%.0f
    ",l*100);
    	}
    	return 0;
    }
    

    POJ2728Desert King 最优比率生成树

    有n个点,每个点有一个坐标和高度
    两点之间的费用是高度之差的绝对值 两点之间的距离就是欧几里得距离
    求一棵生成数,使得单位距离的费用最小

    即求得花费/收益比值最小

    (开始没懂...原来是没好好读题)

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define Abs(x) ((x)<0?-(x):(x))
    #define Max(x,y) ((x)>(y)?(x):(y))
    #define Min(x,y) ((x)<(y)?(x):(y))
    const int N=1000+5,M=5e5+5,INF=1e9+7,inf=0x3f3f3f3f;
    const double eps=1e-7;
    int n,k;
    double a[N][N],b[N][N];
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    struct node{int x,y,h;}nd[N];
    double qdis(int i,int j){return sqrt(1.0*(nd[i].x-nd[j].x)*(nd[i].x-nd[j].x)+1.0*(nd[i].y-nd[j].y)*(nd[i].y-nd[j].y));}
    
    bool vis[N];
    double dis[N],d[N][N];
    double prim(double x){
    	double sum=0.0;
    	for(int i=0;i<=n;++i) dis[i]=1e20,d[i][i]=0.0,vis[i]=0;
    	dis[1]=0.0;
    	for(int i=1;i<=n;++i)
    	for(int j=i+1;j<=n;++j)
    	d[i][j]=d[j][i]=b[i][j]-x*a[i][j];
    	for(int i=1,u=0;i<=n;++i,u=0){
    		for(int j=1;j<=n;++j)
    		if(!vis[j]&&dis[j]<dis[u]) u=j;
    		vis[u]=1,sum+=dis[u];
    		for(int v=1;v<=n;++v)
    		if(!vis[v]) dis[v]=Min(dis[v],d[u][v]);
    	}
    	return sum;
    }
    
    int main(){
    	freopen("in.txt","r",stdin);
    	while(scanf("%d",&n)!=EOF&&n){
    		double l=0.0,r=0.0,mid;
    		for(int i=1;i<=n;++i) rd(nd[i].x),rd(nd[i].y),rd(nd[i].h);
    		for(int i=1;i<=n;++i)
    		for(int j=i+1;j<=n;++j)
    		a[i][j]=a[j][i]=qdis(i,j),b[i][j]=b[j][i]=1.0*Abs(nd[i].h-nd[j].h),r=Max(r,b[i][j]/a[i][j]);
    		while(r-l>=eps){
    			mid=(l+r)/2;
    			if(prim(mid)>0) l=mid;
    			else r=mid;
    		}
    		printf("%.3f
    ",l);
    	}
    	return 0;
    }
    

    USACOSightseeing Cows 最优比率环

    在有向图图中选出一个环,使得这个环的点权/边权最大

    即在每次check的时候找一个正环 可是正环并不好找 就将边权改为负值去找负环

    QQ图片20190815165640.jpg打了一个下午超级悲伤 不知道哪里错了一直给我报错 然后怒而全部删掉重打 然后一遍过... 一言难尽

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define Abs(x) ((x)<0?-(x):(x))
    #define Max(x,y) ((x)>(y)?(x):(y))
    #define Min(x,y) ((x)<(y)?(x):(y))
    const int N=1000+5,M=5000+5,INF=1e9+7,inf=0x3f3f3f3f;
    const double eps=1e-7;
    int n,m,a[N],fr[M],to[M],co[M];
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    int head[N],tot;
    struct edge{int v,nxt;double w;}e[M];
    void add(int u,int v,double w){
    	e[++tot]=(edge){v,head[u],w},head[u]=tot;
    }
    
    bool vis[N];double dis[N];
    int cnt[N];
    queue<int>q;
    bool spfa(){
    	while(!q.empty()) q.pop();
    	for(int i=1;i<=n;++i) dis[i]=0.0,cnt[i]=vis[i]=1,q.push(i);//图有可能不连通
    	while(!q.empty()){
    		int u=q.front();
    		q.pop(),vis[u]=0;
    		for(int i=head[u],v;i;i=e[i].nxt){
    			v=e[i].v;
    			if(dis[v]>dis[u]+e[i].w){
    				dis[v]=dis[u]+e[i].w;
    				if(!vis[v]) q.push(v),vis[v]=1,++cnt[v];
    				if(cnt[v]>=n) return 1;
    			}
    		}
    	}
    	return 0;
    }
    bool check(double x){
    	memset(head,0,sizeof(head)),tot=0;
    	for(int i=1;i<=m;++i) add(fr[i],to[i],-((double)a[to[i]]-x*co[i]));
    	if(spfa()) return 1;//找到负环
    	else return 0;
    }
    
    
    int main(){
    	freopen("in.txt","r",stdin);
    	rd(n),rd(m);
    	for(int i=1;i<=n;++i) rd(a[i]);
    	for(int i=1;i<=m;++i) rd(fr[i]),rd(to[i]),rd(co[i]);
    	double l=0.0,r=3000.0,mid;
    	while(r-l>=eps){
    		mid=(l+r)/2;
    		if(check(mid)) l=mid;
    		else r=mid;
    	}
    	printf("%.2f",l);
    	return 0;
    }
    

    [USACO18OPEN]Talent Show 分数规划+背包

    使总重量最少为W的奶牛可能达到的总才艺值与总重量的比值最大

    01分数规划 然后跑背包来判断是否可行 初始化值时要赋为极小是lch讲的时候强调过的QAQ

    我太瘟辽 该好好练一下动规 在看到重量最少为多少时想了好一会儿怎么转移

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define Abs(x) ((x)<0?-(x):(x))
    #define Max(x,y) ((x)>(y)?(x):(y))
    #define Min(x,y) ((x)<(y)?(x):(y))
    const int N=300+5,M=1000+5,INF=1e9+7,inf=0x3f3f3f3f;
    const double eps=1e-7;
    int n,W,a[N],b[N];
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    double d[N],f[N][M];
    bool check(double mid){
    	for(int i=0;i<=n;++i){
    		if(i) d[i]=(double)a[i]-mid*b[i];
    		for(int j=0;j<=W;++j) f[i][j]=-INF;
    	}
    	f[0][0]=0.0;
    	for(int i=1;i<=n;++i)
    	for(int j=0;j<=W;++j)
    	f[i][j]=Max(f[i][j],f[i-1][j]),
    	f[i][Min(W,j+b[i])]=Max(f[i][Min(W,j+b[i])],f[i-1][j]+d[i]);
    	return f[n][W]>0;
    }
    
    
    int main(){
    	freopen("in.txt","r",stdin);
    	rd(n),rd(W);
    	double l=0.0,r=0.0,mid;
    	for(int i=1;i<=n;++i) rd(b[i]),rd(a[i]),r=Max(r,(double)a[i]/b[i]);
    	while(r-l>=eps){
    		mid=(l+r)/2;
    		if(check(mid)) l=mid;
    		else r=mid;
    	}
    	printf("%d",(int)(l*1000));
    	return 0;
    }
    

    ==还有[SCOI2014]方伯伯运椰子 [SDOI2017]新生舞会 都是分数规划+网络流 懒得做了

  • 相关阅读:
    C语言不进行类型检查 和函数能够不进行前向声明
    EventBus 《二》 Android EventBus的简单使用
    android开发之SnackBar的使用
    iOS语音播放之切换听筒和扬声器
    使用NSURLConnection的网络请求与封装
    Mina Basics 02-基础
    Mina Basics 02-基础
    jquery移除事件,绑定事件,触发事件
    jquery移除事件,绑定事件,触发事件
    jquery移除事件,绑定事件,触发事件
  • 原文地址:https://www.cnblogs.com/lxyyyy/p/11359089.html
Copyright © 2011-2022 走看看