zoukankan      html  css  js  c++  java
  • HDU1203 I NEED A OFFER!0、1背包及空间优化

    I NEED A OFFER!

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 5280    Accepted Submission(s): 1799


    Problem Description
    Speakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校了。要申请国外的任何大学,你都要交纳一定的申请费用,这可是很惊人的。Speakless没有多少钱,总共只攒了n万美元。他将在m个学校中选择若干的(当然要在他的经济承受范围内)。每个学校都有不同的申请费用a(万美元),并且Speakless估计了他得到这个学校offer的可能性b。不同学校之间是否得到offer不会互相影响。“I NEED A OFFER”,他大叫一声。帮帮这个可怜的人吧,帮助他计算一下,他可以收到至少一份offer的最大概率。(如果Speakless选择了多个学校,得到任意一个学校的offer都可以)。
     

    Input
    输入有若干组数据,每组数据的第一行有两个正整数n,m(0<=n<=10000,0<=m<=1000)
    后面的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 '%'.
     
      刚刚学习到背包这个章节,这道题目可以说是在经典背包问题上的一点改进,题中首先将所求值变为了概率 “至少一份offer的最大概率” 现假设被A学校录取概率为 a,被B学校录取概率为 b,则所求概率为1-(1-a)*(1-b), 这个应该好理解吧,知道了这点应该好办了吧,我们把判断条件有经典的相加变为 一个函数的判断:
      float probability(float a,float b)
      {
          return 1-(1-a)*(1-b);
      }
      float t=probability(p[i],c[j-w[i]]); 
               if(t>c[j])
                    c[j]=t;
    有了思路写出代码来:
      
    View Code
    1 #include<stdio.h>
    2 #include<stdlib.h>
    3 #include<math.h>
    4 #include<string.h>
    5 #include<time.h>
    6
    7  float c[1001][10001];
    8  int w[1001];
    9  float p[1001];
    10
    11  float probability(float a,float b)
    12 {
    13 return 1-(1-a)*(1-b);
    14 }
    15
    16 int main()
    17 {
    18 int N,M;
    19 while(scanf("%d%d",&N,&M),M|N)
    20 {
    21 for(int i=0;i<=1000;++i)
    22 for(int j=0;j<=10000;++j)
    23 c[i][j]=0;
    24 for(int i=1;i<=M;++i)
    25 scanf("%d %f",&w[i],&p[i]);
    26 for(int i=1;i<=M;++i)
    27 for(int j=0;j<=N;++j)
    28 {
    29 if(w[i]<=j)
    30 {
    31 float t=probability(p[i],c[i-1][j-w[i]]);
    32 if(t-c[i-1][j]>1e-6)
    33 c[i][j]=t;
    34 else
    35 c[i][j]=c[i-1][j];
    36 }
    37 else
    38 c[i][j]=c[i-1][j];
    39 }
    40 printf("%.1f%%\n",c[M][N]*100);
    41 }
    42 return 0;
    43 }
     
      这样做的结果是超时......
     当然我把10001改成8000 也过了......   看来有时候题中条件是纸老虎啊!!!
        除了“耍赖”还有其他方法吗,答案是肯定的,我们注意到在每次的更新中,看起来好像是依托于上一次的固定值,其实不然,首先每次更新是覆盖了上一次的所有值,也就是上一次的结果已经无须保留,其次此类问题不像数塔般由于在时间或地域上有前后的依赖性,存在一个类似分叉抉择,在数据模拟上(由于有了两个坐标)必须开辟二维数组,但是使用一维数组还有一个地方要改动,就是每次更新从后面开始,即从负荷(在不同的体型中可能是不同的意思)限制大的一端开始,这样就巧妙的利用了用一维数组使用到了二维数组中的“上一次”操作的值了。代码如下:
    View Code
    1 #include<stdio.h>
    2 #include<stdlib.h>
    3 #include<math.h>
    4 #include<string.h>
    5 #include<time.h>
    6
    7 float c[10005];
    8 int w[1001];
    9 float p[1001];
    10
    11 float probability(float a,float b)
    12 {
    13 return 1-(1-a)*(1-b);
    14 }
    15
    16 int main()
    17 {
    18 int N,M;
    19 while(scanf("%d%d",&N,&M),M|N)
    20 {
    21 for(int i=0;i<=10000;++i)
    22 c[i]=0;
    23 for(int i=1;i<=M;++i)
    24 scanf("%d %f",&w[i],&p[i]);
    25 for(int i=1;i<=M;++i)
    26 for(int j=N;j>=0;--j)
    27 {
    28 if(w[i]<=j)
    29 {
    30 float t=probability(p[i],c[j-w[i]]);
    31 if(t>c[j])
    32 c[j]=t;
    33 }
    34 }
    35 printf("%.1f%%\n",c[N]*100);
    36 }
    37 return 0;
    38 }
  • 相关阅读:
    Eclipse下进行SVN提交时报“svn: Transaction is out of date
    【Spring学习】Spring事物管理之aop技术
    【框架学习】ibatis DAO框架分析
    【maven详解-插件】maven 插件机制
    【maven详解-插件】maven插件学习之maven-source-plugin
    关于使用 no-js (Modernizr)
    白话讲MyIsam和InnoDB的区别
    向鼠标右键菜单增加菜单项
    表单提交按钮input和button、a的差异
    MySQL数据库索引的设计原则
  • 原文地址:https://www.cnblogs.com/Lyush/p/2031974.html
Copyright © 2011-2022 走看看