ACM杂题K - I NEED A OFFER!——动态规划_背包问题优化解法
题目描述
Speakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校了。要申请国外的任何大学,你都要交纳一定的申请费用,这可是很惊人的。Speakless没有多少钱,总共只攒了n万美元。他将在m个学校中选择若干的(当然要在他的经济承受范围内)。每个学校都有不同的申请费用a(万美元),并且Speakless估计了他得到这个学校offer的可能性b。不同学校之间是否得到offer不会互相影响。“I NEED A OFFER”,他大叫一声。帮帮这个可怜的人吧,帮助他计算一下,他可以收到至少一份offer的最大概率。(如果Speakless选择了多个学校,得到任意一个学校的offer都可以)。
Input
输入有若干组数据,每组数据的第一行有两个正整数n,m(0<=n<=10000,0<=m<=10000)
后面的m行,每行都有两个数据ai(整型),bi(实型)分别表示第i个学校的申请费用和可能拿到offer的概率。
输入的最后有两个0。Output
每组数据都对应一个输出,表示Speakless可能得到至少一份offer的最大概率。用百分数表示,精确到小数点后一位。
Sample Input
10 3 4 0.1 4 0.2 5 0.3 0 0
Sample Output
44.0%
Hint
You should use printf("%%") to print a '%'.
题目大意
有n万元,够付某些学校的申请费,每个学校的通过率为Pi,先要明确的是至少有一个学校通过的概率 ,最后在m所学校中要找出够付的情况下的
最大值P。
化解成背包问题描述,m个学校为m件商品,每个学校的申请费a为商品质量(或体积),每个学校不录取率为商品的价值,手中有的总钱数n为书包的容量。现在需要在商品
能装进书包的情况下,让装入书包的所有商品的价值的乘积最小。1-P就是最大的被至少一个学校录取的概率。
题解
常规的背包问题的解法设设置一个二维数组a,高位i为商品个数,低位j为书包容积数,储存的是对于第i件商品,书包容积为j时可以储存的商品价值成绩的最小值(常规题目思想是商品价值和的最大值)。运用两个for循环来填充数组a,外层循环为商品个数,内层循环书包容积数,判断条件为当前商品的体积money[i]<=容积j,检查更新公式: (含义为不装入当前商品i时和装入商品i时哪个价值总乘积最小,把最小的赋给当前值)。否则体积大于容积就等于不装入该商品的最小值a[i-1][j].
这个方法的问题在于当商品数很多、书包容积很大时数组开得太大会爆掉内存,而且当当前商品体积小于容积是没有操作的,浪费大量了的时间和空间。因此将数组化简成一维,只存放对于当前体积j的最小的商品价值乘积的最小值,还是用两个for循环,外层商品数,内层体积数来遍历,内循环控制为最大容积到当前商品的体积,这样避免判断商品不能装入书包的情况(无法装入自然不会更新,所以可以直接不判断),检查更新数组a的公式为 。同时记录更新最小值,最后for循环遍历完之后输出(1-最小值)即可。
ps:本篇文章暂时只讨论了0-1背包问题(同类商品只有一个)
代码
#include<iostream>
#include<iomanip>
using namespace std;
struct offer
{
int mon;
double realp; //是用1-p得到的,真正用于计算的“商品的价值”
double p;
};
double mymin(double x,double y)
{
if(x<y)
return x;
else
return y;
}
int main()
{
int n=0,m=0;
cin>>n>>m;
while(n!=0 || m!=0)
{
offer *x=new offer[m+1];
double *maxx=new double [n+1];
for(int i=1;i<=m;i++)
{
cin>>x[i].mon>>x[i].p;
x[i].realp=1-x[i].p;
}
for(int i=0;i<=n;i++)
maxx[i]=1.0;
double big=1.0;
for(int i=1;i<=m;i++)
{
for(int j=n;j>=x[i].mon;j--)
{
maxx[j]=mymin(maxx[j],maxx[j-x[i].mon]*x[i].realp);//j容量将能装入的
if(maxx[j]<big)
big=maxx[j];
}
}
cout<<setiosflags(ios::fixed)<<setprecision(1)<<(1-big)*100<<"%"<<endl;
cin>>n>>m;
}
return 0;
}