博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
编程之美第一篇 01分数规划
阅读量:6930 次
发布时间:2019-06-27

本文共 4835 字,大约阅读时间需要 16 分钟。

01分数规划

01分数规划问题其实就是解决单价之类的问题,假设给你n个物品,让你找出选k个物品的最大单价;例如南阳oj:Yougth的最大化;解决这类问题可以用二分查找,这类问题跟二分极大化最小值,极小化最大值有一些相似的地方,均是从结果出发,来进行二分查找;例如上面南阳那道题,可以转化一下;

由于v/w=单价;所以v=w*单价;即v-w*单价=0;有了这个关系,我们马上可以想到二分来查找这个值;

那么我们可以定义一个count数组来记录v-w*单价的值;由于选k个只需要把count从大到小排下序就可以了;然后就是二分了;这类问题就是01分数规划问题;

代码实现:

#include
#include
#define MAX(x,y) x>y?x:yusing namespace std;const int MAXN=10010;struct Node{int v,w;};Node res[MAXN];double cont[MAXN];int n,k;int fun(double mid){
for(int i=0;i
=n-k;i--)sum+=cont[i]; //printf("%lf\n",mid); return sum>=0?1:0;}double abs(double x){ return x>0?x:-x;}double search(double max){
double left=0,right=max,mid; while(right-left>1e-10){mid=(left+right)/2; if(fun(mid))left=mid; else right=mid; } return mid;}int main(){ while(~scanf("%d%d",&n,&k)){double max=0; for(int i=0;i

  与这个题相似的还有poj Dropping tests;这个题意是:

给你n个数,让求删除k个数后

的最大值;

跟南阳那个题很相似,只需要找n-k个数即可;

代码实现:

#include
#include
#include
#include
#include
using namespace std;const int MAXN=10010;struct Node{ int a,b;};Node dt[MAXN];double d[MAXN];int n,k;bool fsgh(double R){ double sum=0; for(int i=0;i
=n-k;i--)sum+=d[i]; return sum>0?true:false;}double erfen(double l,double r){ double mid; while(r-l>1e-6){ mid=(l+r)/2; if(fsgh(mid))l=mid; else r=mid; } return mid;}int main(){ while(scanf("%d%d",&n,&k),n|k){ double mx=0; k=n-k; for(int i=0;i

  另外01分数规划还可以与图论结合在一起;例如:

和最小生成树结合在一起让你求一棵最优比率生成树;例如 poj Desert King;

题意:有N个村庄,给出每个村庄的坐标和海拔,benifit为两点之间的距离,cost为两点的高度差,现在要求一棵树使得 cost / benift 最小

咋一看跟01分数规划还真像,但是让求的是一棵树,我们该怎么办?其实就是求一个最小生成树罢了,最小生成树里面的low数组代表的是啥?权值!那直接把low数组里面的值换成cost-benift*R就好了,然后就是一个二分问题了;

代码实现:

#include
#include
#include
#include
#include
#define mem(x,y) memset(x,y,sizeof(x))using namespace std;const int INF=0x3f3f3f3f;typedef long long LL;const int MAXN=1010;double vis[MAXN],low[MAXN];int N;double R;struct Node{ double x,y,h;};Node dt[MAXN];double len[MAXN][MAXN],cost[MAXN][MAXN];double getl(Node a,Node b){ double x=b.x-a.x,y=b.y-a.y; return sqrt(x*x+y*y);}bool prime(){ double total; mem(vis,0); for(int i=0;i
cost[k][j]-R*len[k][j])low[j]=cost[k][j]-R*len[k][j]; } //printf("total=%lf R=%lf\n",total,R); if(total>0)return true; else return false;}int main(){ while(scanf("%d",&N),N){ mem(len,INF); mem(cost,INF); double mxl=-INF,mil=INF,mxc=-INF,mic=INF; for(int i=0;i
1e-4){ R=(l+r)/2; if(prime())l=R; else r=R; } printf("%.3f\n",l); } return 0;}

另外01分数规划还可以与最短路结合在一起;求一个最优比率环;例如poj Sightseeing Cows;

题意:这个人带牛旅行,旅行每个城市会有幸福度,通过每个城市会花费时间,让找平均每秒的最大幸福度;

注意这题是让求最大的,好像我们前面讲的都是最小的,那该怎么办呐?很简单以前是hp-R*t;转成R*t-hp不就好了吗?照样转化成最短路问题;但是可能产生负边啊;对了就是负边,二分就是从负边出发的,有负边证明t太大,没有t小,这就是二分的一个条件;由于负边我们可以用bellman,或者邻接表解决;

代码实现:

#include
#include
#include
#include
#include
#include
#define mem(x,y) memset(x,y,sizeof(x))using namespace std;const int INF=10000000000000;typedef long long LL;const int MAXN=1010;const int MAXM=100010;/*struct Node{ int u,v; double t;}; Node dt[MAXM];*/struct Edge{ int from,to,next,t;};Edge edg[MAXM];int head[MAXM];int edgnum;void add(int u,int v,int t){ Edge E={u,v,head[u],t}; edg[edgnum]=E; head[u]=edgnum++;}int L,P;double hp[MAXN],dis[MAXN];int usd[MAXN],vis[MAXN];/*void add(int u,int v,double t){ Node E={u,v,t}; dt[edgnum++]=E;}*///double R;/*bool Bellman(){ mem(dis,INF); mem(usd,0); dis[1]=0; while(1){ int temp=0; for(int j=0;j
dis[u]+R*t-hp[u])usd[v]++,dis[v]=dis[u]+R*t-hp[u],temp=1; if(usd[v]>L)return false; } if(!temp)return true; }}*/bool SPFA(double R){ queue
dl; while(!dl.empty())dl.pop(); for(int i=1;i<=L;i++){ dis[i]=INF; vis[i]=0; usd[i]=0; } dl.push(1); vis[1]=1; usd[1]++; dis[1]=0; while(!dl.empty()){ int u=dl.front(); dl.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=edg[i].next){ int v=edg[i].to,t=edg[i].t; if(dis[v]>dis[u]+R*t-hp[u]){ dis[v]=dis[u]+R*t-hp[u]; if(!vis[v]){ vis[v]=1; usd[v]++; dl.push(v); // printf("%d\n",usd[v]); if(usd[v]>=L)return false; } } } } return true;}int main(){ int a,b; int c; while(~scanf("%d%d",&L,&P)){ edgnum=0; double mih=INF,mxh=-INF; int mit=INF,mxt=-INF; mem(head,-1); for(int i=1;i<=L;i++){ scanf("%lf",hp+i); mih=min(mih,hp[i]); mxh=max(mxh,hp[i]); } while(P--){ scanf("%d%d%d",&a,&b,&c); add(a,b,c); mit=min(mit,c); mxt=max(mxt,c); } double l=mih/mxt,r=mxh/mit; // printf("%f %f\n",l,r); double R; while(r-l>=0.001){ R=(l+r)/2; if(SPFA(R))r=R; else l=R; } printf("%.2f\n",l); } return 0;}

01分数规划是一个基本而且有用的算法,可以与图论连用,也可以与数据结构一起用;

上面提到的题解详情请见:

转载请附上地址:

你可能感兴趣的文章
C#设计模式之二十二备忘录模式(Memento Pattern)【行为型】
查看>>
Python之进度条
查看>>
android mvp高速开发框架介绍(dileber使用之图片下载工具)
查看>>
C#钩子类 几乎捕获键盘鼠标所有事件
查看>>
Netty4.0学习笔记系列之一:Server与Client的通讯
查看>>
字符串格式化
查看>>
Win8 Metro(C#)数字图像处理--2.46图像RGB分量增强效果
查看>>
Golang语言
查看>>
Ionic3的http请求如何实现token验证,并且超时返回登录页
查看>>
Spring Boot 版本支持对应JDK
查看>>
基于 IJKPlayer-concat 协议的视频无缝拼接技术实现
查看>>
JavaScript编程(终极篇)
查看>>
2018第13周总结
查看>>
重启ssh服务出现Redirecting to /bin/systemctl restart sshd.service
查看>>
Java线程学习总结
查看>>
visual studio code 的必装推荐插件plugin, vscode, vsc
查看>>
利用CVE-2018-0950漏洞自动窃取Windows密码
查看>>
Linux命令_磁盘管理_查看磁盘或目录的容量
查看>>
网络模型 - 每天5分钟玩转 Docker 容器技术(169)
查看>>
浏览器实时刷新工具
查看>>