DP(1) 背包

01背包模型

1 for (int i=1;i<=n;i++)
2   for (int j=1;j<=Max_c;j++)
3     f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+value[i]);
01背包 转移方程

1.[noip2005pj]采药

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 
 6 int time[105],value[105],f[105][1005];
 7 
 8 int main()
 9 {
10     int maxtime,tot;
11     scanf("%d%d",&maxtime,&tot);
12     for (int i=1;i<=tot;i++)
13       scanf("%d%d",&time[i],&value[i]);
14     
15     memset(f,0,sizeof(f));
16     for (int i=1;i<=tot;i++)
17       for (int j=1;j<=maxtime;j++)
18       {
19           f[i][j]=f[i-1][j];
20           if (j>=time[i])
21             f[i][j]=max(f[i][j],f[i-1][j-time[i]]+value[i]);
22       }
23       
24     printf("%d",f[tot][maxtime]);
25     return 0;
26 }
View Code

2.[vijos1037]搭建双塔

题意:在n个数中选取若干个求和,得到两个相等的数,求最大数

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 
 6 bool f[100][2005][2005];
 7 int h[105];
 8 int main()
 9 {
10     int n;
11     scanf("%d",&n);
12     memset(h,0,sizeof(h));
13     int tot=0;
14     for (int i=1;i<=n;i++){
15       scanf("%d",&h[i]);
16       tot+=h[i];
17     }
18     tot/=2;
19     tot++;
20     memset(f,0,sizeof(f));
21     f[0][0][0]=1;
22     for (int i=1;i<=n;i++)
23       for (int j=0;j<=tot;j++)
24         for (int k=0;k<=tot;k++){
25           f[i][j][k]=f[i-1][j][k];
26           if (j>=h[i]) f[i][j][k]=f[i][j][k]||f[i-1][j-h[i]][k];
27           if (k>=h[i]) f[i][j][k]=f[i][j][k]||f[i-1][j][k-h[i]];
28     }
29     int num=tot;
30     while (num>0) 
31     {
32         if (f[n][num][num]==1) break;
33         num--;
34     } 
35     if (num!=0) printf("%d\n",num);
36     else printf("Impossible");
37     return 0;
38 }
RE一个点

f[i][j]表示前i块水晶,两塔高度差为j时,较低塔的高度

目标状态为f[n][0]

则对于h[i]需考虑四种情况:(可画图帮助理解)

1)不取 f[i][j]=f[i-1][j]

2)放在较低塔上,仍是较低的 f[i][j]=max(f[i][j],f[i-1][j+h[i]]+h[i])

3)放在较低塔上,变成较高的 f[i][j]=max(f[i][j],f[i-1][h[i]-j]+h[i]-j)

4)放在较高塔上  f[i][j]=max(f[i][j],f[i-1][j-h[i]])

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

int f[105][2005],h[105];
int main(){
    int n,tot=0;
    scanf("%d",&n);
    for (int i=1;i<=n;i++){
      scanf("%d",&h[i]);
      tot+=h[i];
    }
    memset(f,-1,sizeof(f));
    f[0][0]=0;
    for (int i=1;i<=n;i++)
        for (int j=0;j<=tot;j++){
            if (f[i-1][j]!=-1) f[i][j]=f[i-1][j];
            if (f[i-1][j+h[i]]!=-1) f[i][j]=max(f[i][j],f[i-1][j+h[i]]+h[i]);
            if (j>=h[i]&&f[i-1][j+h[i]!=-1]) f[i][j]=max(f[i][j],f[i-1][j-h[i]]);
            if (h[i]>=j&&f[i-1][h[i]-j]!=-1) f[i][j]=max(f[i][j],f[i-1][h[i]-j]+h[i]-j);
        }
    int num=tot;
    if (f[n][0]>0) printf("%d",f[n][0]);
    else printf("Impossible");
    return 0;
}
AC

3.[noip2007tg] 金明的预算方案

有依赖的背包

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

int price[65],imp[65];
int infor[60][4];
int f[60][3500];

//预处理:a.主件,附件
//           b.数字除以10
int main(){
    int n,m,a,b,c;
    memset(infor,0,sizeof(infor));
    scanf("%d%d",&n,&m);
    n/=10;
    for (int i=1;i<=m;i++){
        scanf("%d%d%d",&price[i],&imp[i],&c);
        price[i]/=10;
        imp[i]*=price[i];
        if (c==0) infor[i][0]=1;
        else{//是附件
          infor[i][0]=0;
          infor[c][3]++;
          infor[c][infor[c][3]]=i;
        }
    }
    int Last=0;
    memset(f,0,sizeof(f));
    for (int i=1;i<=m;i++){
        if (infor[i][0]==0) continue;
        for (int j=0;j<=n;j++){
             f[i][j]=f[Last][j];
            //不取主件 
             if (j>=price[i]) f[i][j]=max(f[i][j],f[Last][j-price[i]]+imp[i]);
            //只取主件 
             if (infor[i][3]>0&&j>=price[i]+price[infor[i][1]])
               f[i][j]=max(f[i][j],f[Last][j-price[i]-price[infor[i][1]]]+imp[i]+imp[infor[i][1]]);
             //取主件和第一件附件  
             if (infor[i][3]==2&&j>=price[i]+price[infor[i][2]])
               f[i][j]=max(f[i][j],f[Last][j-price[i]-price[infor[i][2]]]+imp[i]+imp[infor[i][2]]);
            //取主件和第二件附件
            if (infor[i][3]==2&&j>=price[i]+price[infor[i][1]]+price[infor[i][2]])
               f[i][j]=max(f[i][j],f[Last][j-price[i]-price[infor[i][1]]-price[infor[i][2]]]+imp[i]+imp[infor[i][1]]+imp[infor[i][2]]);     
             //取主件和两件附件  
        }
        Last=i;
    }
    printf("%d",f[Last][n]*10);
    return 0; 
} 
View Code

总结:注意考虑到多种情况,还有各种小技巧的使用

posted @ 2016-11-08 16:44  Vincent_hwh  阅读(179)  评论(0编辑  收藏  举报