CCF NOIP2014前的复习(10.20)

2014.10.20

     继续复习DP

    Noip2006考了一道《金明的预算方案》,有依赖背包问题,再做做。

描述 Description 

      金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:

主件   附件

电脑   打印机,扫描仪

书柜   图书

书桌   台灯,文具

工作椅 

  如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有0个、1个或2个附件。附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的N元。于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是10元的整数倍)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

 

设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1j2,……,jk,则所求的总和为:v[j1]*w[j1]+v[j2]*w[j2]++v[jk]*w[jk]。(其中*为乘号)请你帮助金明设计一个满足要求的购物单。

输入格式 Input Format   

      输入文件的第1行,为两个正整数,用一个空格隔开:

N  m

其中N<32000)表示总钱数,m<60)为希望购买物品的个数。

从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有3个非负整数

v  p  q

(其中v表示该物品的价格(v<10000),p表示该物品的重要度(1~5),q表示该物品是主件还是附件。如果q=0,表示该物品为主件,如果q>0,表示该物品为附件,q是所属主件的编号)

输出格式 Output Format  

       输出文件只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值

<200000)。

样例输入 Sample Input   

 1000 5

800 2 0

400 5 1

300 5 1

400 3 0

500 2 0

样例输出 Sample Output  

2200

时间限制 Time Limitation

    1s

来源 Source  

    NOIP2006第二题

分析:标准解法为有依赖性背包问题。

还有一种取巧方法,将每个主件及其附件的所有选择方案分为一个组,然后整体做分组背包,因为这道题的附件最多两个,所以可以这么做,只需预处理出所有组即可。

    我写了依赖性背包的解法,主要思想就是对一个主件的所有附件做01背包,求出每个主件的最优解,然后对每个主件做01背包即可。

代码如下:

#include
#include
#include
#include
#include
using namespace std;
int N,M,a[41000],f[41000];
int v[70],w[70],p[70];
void init()
{
   scanf("%d%d",&N,&M);
   for(int i=1;i<=M;i++)
   {
      scanf("%d%d%d",&v[i],&w[i],&p[i]);
      w[i]*=v[i];
   }
}
void DP()
{
   for(int i=1;i<=M;i++)
      if(p[i]==0)
      {
         for(int j=1;j=v[i]+v[j];k--)
                   if(a[k-v[j]]+w[j]>a[k]) a[k]=a[k-v[j]]+w[j];
         for(int j=v[i];j<=N;j++)
            if(a[j]>f[j]) f[j]=a[j];
      }
   printf("%d\n",f[N]);
}
int main()
{
   init();
   DP();
   return 0;
}

   看看分组背包,有一道竞赛真理,比较简单。

描述 Description 

    牛玉鑫在经历了无数次学科竞赛的失败以后,得到了一个真理:做一题就要对一题!但是要完全正确地做对一题是要花很多时间(包括调试时间),而竞赛的时间有限。所以开始做题之前最好先认真审题,估计一下每一题如果要完全正确地做出来所需要的时间,然后选择一些有把握的题目先做。 当然,如果做完了预先选择的题目之后还有时间,但是这些时间又不足以完全解决一道题目,应该把其他的题目用贪心之类的算法随便做做,争取“骗”一点分数。

问题求解:

根据每一题解题时间的估计值,确定一种做题方案(即哪些题目认真做,哪些题目“骗”分,哪些不做),使能在限定的时间内获得最高的得分,

输入格式 Input Format   

    根据每一题解题时间的估计值,确定一种做题方案(即哪些题目认真做,哪些题目“骗”分,哪些不做),使能在限定的时间内获得最高的得分,从文件读入数据。第一行有两个正整数NT,表示题目的总数以及竞赛的时限(单位秒)。以下的N行,每行4个正整数W1i  T1i W2i  T2i,分别表示第i题:完全正确做出来的得分,完全正确做出来所花费的时间(单位秒),“骗”来的分数,“骗”分所花费的时间(单位秒)。

  其中,3N302T10800001 W1i W2i 300001T1iT2iT

输出格式 Output Format  

    直接把所能得到的最高分值输出到文件TRUTH.OUT,文件只有一行(包括换行符)。

输入格式 Input Format   

    根据每一题解题时间的估计值,确定一种做题方案(即哪些题目认真做,哪些题目“骗”分,哪些不做),使能在限定的时间内获得最高的得分,从文件读入数据。第一行有两个正整数NT,表示题目的总数以及竞赛的时限(单位秒)。以下的N行,每行4个正整数W1i  T1i W2i  T2i,分别表示第i题:完全正确做出来的得分,完全正确做出来所花费的时间(单位秒),“骗”来的分数,“骗”分所花费的时间(单位秒)。

  其中,3N302T10800001 W1i W2i 300001T1iT2iT

输出格式 Output Format  

    直接把所能得到的最高分值输出到文件TRUTH.OUT,文件只有一行(包括换行符)。

样例输入 Sample Input   

样例1

4 10800

18 3600 3 1800

22 4000 12 3000

28 6000 0 3000

32 8000 24 6000

样例2

3 7200

50 5400 10 900

50 7200 10 900

50 5400 10 900

样例输出 Sample Output  

样例1

50

样例2

70

时间限制 Time Limitation

    1s

分析:每组中物品很少,只要分情况讨论即可(优先选择认真做的)。

代码如下:

#include
#include
#include
#include
#include
using namespace std;
int n,T,f[1080005];
void init()
{
   memset(f,0,sizeof(f));
   cin>>n>>T;
}
void work()
{
   for(;n>0;n--)
   {
      int w1,t1,w2,t2;
      cin>>w1>>t1>>w2>>t2;
      for(int j=T;j>=0;j--)
      {
         if(j>=t1) f[j]=max(f[j],f[j-t1]+w1);//优先选择得全分
            if(j>=t2) f[j]=max(f[j],f[j-t2]+w2);
      }
   }
   cout<

你可能感兴趣的:(CCF NOIP2014前的复习(10.20))