01分数规划

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

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

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

代码实现:

#include<stdio.h>
#include<algorithm>
#define MAX(x,y) x>y?x:y
using 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;i++){cont[i]=res[i].v-mid*res[i].w;}sort(cont,cont+n);double sum=0;for(int i=n-1;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<n;i++){scanf("%d%d",&res[i].w,&res[i].v);max=MAX(max,res[i].v*1.0/res[i].w);//        }printf("%.2f\n",search(max));}return 0;
}

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

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

的最大值;

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

代码实现:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
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;i++)d[i]=dt[i].a-R*dt[i].b;sort(d,d+n);for(int i=n-1;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<n;i++)scanf("%d",&dt[i].a);for(int i=0;i<n;i++)scanf("%d",&dt[i].b),mx=max(1.0*dt[i].a/dt[i].b,mx);printf("%.0f\n",erfen(0,mx)*100);}return 0;
}

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

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

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

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

代码实现:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#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<N;i++)low[i]=cost[0][i]-R*len[0][i];total=0;vis[0]=1;//    for(int i=0;i<N;i++){double temp=INF;int k;for(int j=0;j<N;j++)if(!vis[j]&&low[j]<temp)temp=low[j],k=j;if(temp==INF)break;total+=temp;vis[k]=1;for(int j=0;j<N;j++)if(!vis[j]&&low[j]>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<N;i++)scanf("%lf%lf%lf",&dt[i].x,&dt[i].y,&dt[i].h);for(int i=0;i<N;i++){for(int j=i+1;j<N;j++){len[j][i]=len[i][j]=getl(dt[i],dt[j]);cost[j][i]=cost[i][j]=abs(dt[i].h-dt[j].h);mxl=max(mxl,len[i][j]);mxc=max(mxc,cost[i][j]);mil=min(mil,len[i][j]);mic=min(mic,cost[i][j]);}}//printf("%lf %lf %lf %lf\n",mil,mic,mxl,mxc);double l=mic/mxl,r=mxc/mil;        //    printf("%lf %lf\n",l,r);while(r-l>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<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#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<edgnum;j++){int u=dt[j].u,v=dt[j].v;double t=dt[j].t;//dis[v]=min(dis[v],dis[u]+R*t-hp[u]);//应该是R*t-hp[u]; if(dis[v]>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<int>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分数规划是一个基本而且有用的算法,可以与图论连用,也可以与数据结构一起用;

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

http://www.cnblogs.com/handsomecui/p/4690691.html

http://www.cnblogs.com/handsomecui/p/4971467.html

http://www.cnblogs.com/handsomecui/p/4972701.html

http://www.cnblogs.com/handsomecui/p/4973041.html

转载请附上地址:

http://www.cnblogs.com/handsomecui

转载于:https://www.cnblogs.com/handsomecui/p/5116886.html

编程之美第一篇 01分数规划相关推荐

  1. 转载二分 01 分数规划即最大化平均值的证明0/1分数规划、最优比率生成树、最优比率环

    首页 新随笔 联系 管理 订阅 随笔- 20  文章- 0  评论- 9 [Algorithm]01分数规划--Update:2012年7月27日 [关键字] 0/1分数规划.最优比率生成树.最优比率 ...

  2. 【转】0-1分数规划等问题

    [关键字] 0/1分数规划.最优比率生成树.最优比率环 [背景] 根据楼教主的回忆录,他曾经在某一场比赛中秒掉了一道最优比率生成树问题,导致很多人跟风失败,最终悲剧.可见最优比率生成树是多么凶残的东西 ...

  3. [Algorithm]01分数规划

    [关键字] 0/1分数规划.最优比率生成树.最优比率环 [背景] 根据楼教主的回忆录,他曾经在某一场比赛中秒掉了一道最优比率生成树问题,导致很多人跟风失败,最终悲剧.可见最优比率生成树是多么凶残的东西 ...

  4. 【图论专题】负环与01分数规划

    整理的算法模板合集: ACM模板 题目列表: 题目 算法 AcWing 904. 虫洞 spfa判负环 AcWing 361. 观光奶牛 最优比率环.01分数规划 AcWing 1165. 单词环 0 ...

  5. POJ2728 Desert King ——01分数规划Dinkelbach迭代法+最小生成树prim算法

    首先,纪念我用Linux系统AC的第一题-   安装这个万恶的NOI Linux系统费了6小时的时间,不过好在最后终于装上了,但是因为我安装的Linux系统比较烂,还遭到了小花儿和js的鄙视,唉,本人 ...

  6. codevs1183 泥泞的道路(01分数规划)

    1183 泥泞的道路  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description CS有n个小区,并且任意小区之间都有两 ...

  7. Bailian4145 放弃考试 POJ2976 ZOJ3068 Dropping tests【二分法+01分数规划】

    4145:放弃考试 总时间限制: 1000ms 内存限制: 65536kB 描述 在一门课程中,一共有n场考试.假如你在i场考试中可以答对bi道题中的ai道,那么你的累计平均分定义为:100·Σai/ ...

  8. UPC 小澳的葫芦 (最短路+01分数规划 )

    不懂01分数规划的可以先看大佬博客~ 传送门 01分数规划,即给定模型求sum(ai)/sum(bi)的最值: 我们可以改变一下式子的形态: sum(ai)/sum(bi)>=L =sum(ai ...

  9. [COGS2652]秘术「天文密葬法」-长链剖分-01分数规划

    秘术「天文密葬法」 题目说明: 路径的长度是点数 所有整数都是正整数 已添加一句话题意 [题目描述] 永琳需要协助紫解决异变! 在某个满月的夜晚,幻想乡的结界出现了异常,虽然目前还没有找到原因,不过有 ...

  10. 【BZOJ 4819】 4819: [Sdoi2017]新生舞会 (0-1分数规划、二分+KM)

    4819: [Sdoi2017]新生舞会 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 601  Solved: 313 Description 学 ...

最新文章

  1. ML顶会论文都可复现吗?来挑战一下,还能拿500美元补贴
  2. Linux之chattr命令详解
  3. 无线网络的网速很慢_家里无线网络每天不定时段出现网速很慢或者直接无连接,这是怎么回事?...
  4. linux性能分析资源推荐(重要)
  5. Oracle Goldengate ORA-21780故障处理
  6. wordpress 静态化 linux,WordPress如何静态化
  7. js页面加载之前触发的事件
  8. java内存高水位_jvm(1)---java内存结构
  9. 众望所归!中国机器狗能【后空翻】了。。。
  10. 浅入浅出数据结构(20)——快速排序
  11. (八)深入浅出TCPIP之TCP长连接与短连接详解
  12. 2020胡润慈善榜揭晓:许家印以28亿元捐赠额成为中国首善
  13. python hashlib_python hashlib模块
  14. springcloud(十):服务网关zuul初级篇
  15. 参加了 InfoQ 的虚拟座谈会
  16. 数据结构——第九章 查找
  17. 机刷实名认证软件_代刷网已上架抖音代实名认证和抖音音乐人认证
  18. ArcGIS教程:按单个值进行重分类
  19. 域名备案和网站备案有什么区别?
  20. linux公社_如何在Linux上搭建个人流媒体服务器

热门文章

  1. 海蜘蛛理由器做端口映射
  2. 理解OAuth 2.0[摘]
  3. MANIFEST.MF文件的编辑注意事项
  4. 用R读取Excel的新方法
  5. 关于ADO之AddNew,UPdate与Identity列
  6. java.lang.Classlt;Tgt;
  7. 产品经理给程序员发了一个“在吗”
  8. GitHub 热榜:文字识别神器,超轻量级中文 OCR!一个超级厉害的开源库
  9. 盘点各种程序员常用的框架,看看你是否落伍了?
  10. 算法图解 各部分回忆