1.背包问题(模板)

   经典的背包九讲:http://love-oriented.com/pack/

  01背包,完全背包,多重背包。

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <string.h>
 4 using namespace std;
 5 
 6 const int MAX=100000;
 7 int dp[MAX];
 8 int c[MAX],w[MAX];
 9 int v;
10 
11 void ZeroOnePack(int cost,int wei)       //01背包
12 {
13     int i;
14     for(i = v;i>=cost;i--)
15     {
16         dp[i] = max(dp[i],dp[i-cost]+wei);
17     }
18 }
19 
20 void CompletePack(int cost,int wei)      //完全 背包
21 {
22     int i;
23     for(i = cost;i<=v;i++)
24     {
25         dp[i] = max(dp[i],dp[i-cost]+wei);
26     }
27 }
28 
29 void MultiplePack(int cost,int wei,int cnt)   //多重 背包
30 {
31     if(v<=cnt*cost)//如果总容量比这个物品的容量要小,那么这个物品可以直到取完,相当于完全背包
32     {
33         CompletePack(cost,wei);
34         return ;
35     }
36     else//否则就将多重背包转化为01背包
37     {
38         int k = 1;
39         while(k<=cnt)
40         {
41             ZeroOnePack(k*cost,k*wei);
42             cnt = cnt-k;
43             k = 2*k;
44         }
45         ZeroOnePack(cnt*cost,cnt*wei);
46     }
47 }
48 
49 int main()
50 {
51     int n;
52     while(~scanf("%d%d",&n,&v),n+v)
53     {
54         int i;
55         for(i = 0;i<n;i++)
56         scanf("%d",&c[i]);
57         for(i = 0;i<n;i++)
58         scanf("%d",&w[i]);
59         memset(dp,0,sizeof(dp));
60         for(i = 0;i<n;i++)
61         {
62             MultiplePack(c[i],c[i],w[i]);
63         }
64         int sum = 0;
65         for(i = 1;i<=v;i++)
66         {
67             if(dp[i]==i)
68             {
69                 sum++;
70             }
71         }
72         printf("%d\n",sum);
73     }
74     return 0;
75 }
View Code

 二维背包

   hdu 2159  

 思路:这题是一道典型的二维完全背包题,很明显,背包内所要储存的是经验,所以背包的容量便以忍耐度与杀怪数作为标准,每次得到背包价值的最大数与升级所需的经验作比较,  能够升级就退出。

 1  #include<cmath>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 
 7 using namespace std;
 8 const int maxn = 200;
 9 int n , m , k , s;
10 int a[maxn] , b[maxn] , dp[maxn][maxn];
11 
12 int main()
13 {
14     while(scanf("%d%d%d%d", & n, &m, &k, &s)  !=EOF)
15     {
16         memset(dp , 0 , sizeof(dp));
17         for(int i = 1;i <= k;i ++)
18         {
19             scanf("%d%d", &a[i] , &b[i]);
20         }
21         int i , j , z;
22         for(i = 1;i <= m;i ++)    // 主要限制要放在种数前
23         {
24             for(j = 1;j <= k;j ++)
25             {
26                 for(z = 1;z <= s;z ++)
27                 {
28                     int ans = 1;
29                     while(ans * b[j] <= i && ans <= z)  
30                     {  
31                         dp[i][z] = max(dp[i][z],dp[i - ans * b[j]][z-ans] + ans*a[j]);  
32                         ans ++;  
33                     }  
34                 }    
35             }
36             if(dp[i][s] >= n)
37               break;
38         }
39         if(i > m)
40           printf("-1\n");
41         else
42           printf("%d\n",m - i);
43     }
44     return 0;
45 }
View Code 

2LISLCS

      最长递增子序列,朴素的是O(n^2)算法,二分下可以写成O(nlgn):维护一个当先最优的递增序列——找到恰好大于它更新。

  最长公共子序列,通常O(n^2)