寒假集训之 背包问题

任何东西题目还是要做滴~

POJ 3624

http://poj.org/problem?id=3624

我刚开始用了结构体来做,结果就MLE了。唉,看了别人的AC代码发现就数组,后来查了一下,发现结构体用不好就特别占内存

 1 #include <cstdio>
 2 #include <cstring>
 3 
 4 using namespace std;
 5 
 6 int n,m,w,v;
 7 const int N = 13000;
 8 int dp[N] = {};
 9 
10 int main(){
11     scanf("%d%d",&n,&m);
12     memset(dp,0,sizeof(dp));
13     for(int i = 1;i <= n;i++){
14         scanf("%d%d",&w,&v);
15         for(int j = m;j >= w;j--){
16             int tmp = dp[j-w]+v;
17             if(tmp > dp[j]){
18                 dp[j] = tmp;
19             }
20         }
21     }
22     printf("%d\n",dp[m]);
23 }
View Code

POJ 3628

http://poj.org/problem?id=3628

这道题刚开始也MLE,真想友尽。

每个数据都是long long,然后申请了20000000个数组空间,算算也是超内存了,然后还memset了一遍,据说这个很占内存?

后来想想反正没有多组数据测试,而且全局申请的变量默认是0,就直接注释掉了。

刚开始直接把每个数据都算了一遍都往原数组存,估计就是这里MLE了

我看了别人的AC代码,另外开了一个数组,估计有很多空出来。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 const int N = 20000000 + 3;
 8 
 9 int n,b,a,s;
10 int h[20 + 3] = {};
11 int dp[N] = {};
12 
13 int main(){
14   scanf("%d%d",&n,&b);
15   //memset(h,0,sizeof(h));
16     for(int i = 1;i <= n;i++){
17         scanf("%d",&h[i]);
18         s += h[i];
19     }
20     for(int i = 1;i <= n;i++){
21         for(int j = s;j >= h[i];j--){
22             dp[j] = max(dp[j],dp[j-h[i]]+h[i]);
23         }
24     }
25     int minn = 10000000;    
26     for(int i = s;i >= b;i--){
27         if(dp[i] - b < minn && dp[i] - b >= 0){
28             minn = dp[i] -b;
29         }
30     }
31     printf("%d\n",minn);
32 }
View Code

POJ 1837

http://poj.org/problem?id=1837

这道题刚开始题意都看不懂,因为英文实在太菜了T_T

后来直接搜题解,看到这个图瞬间懂了(出处:http://blog.csdn.net/hopeztm/article/details/7858622)

寒假集训之 背包问题_第1张图片

就是让两端平衡而已,只不过杆子不一定只有两根。

然后又看了一篇博客(http://www.cnblogs.com/kedebug/archive/2013/01/22/2871707.html)总算看懂

其中我看了很多人的代码,都写着15000和7500.我想了很久才想通这是怎么来的。

假设我们把所有的东西都挂在一端一根杆子上,最大的C*最大的G*最大的单个物体的重量 = 15 * 20 * 25 = 15000

我敢说绝大多数的博客没有解释这15000是怎么来的(自恋脸),好吧,我的猪脑太笨了

接着我们首先把7500当成中间状态,因为左边的是负数,这样我们再分别往左右两边挂东西。

下面我们把话筒交给dp~

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 
 5 #define MAXN 15000
 6 
 7 using namespace std;
 8 
 9 const int N = 25;
10 
11 int c,g;
12 int a[N],b[N];
13 int dp[N][MAXN] = {};
14 
15 
16 int main(){
17     scanf("%d%d",&c,&g);
18     for(int i = 1; i <= c;i++){
19         scanf("%d",&a[i]);
20     }
21     for(int i = 1;i <= g;i++){
22         scanf("%d",&b[i]);
23     }
24     memset(dp,0,sizeof(dp)); 
25     dp[0][MAXN>>1] = 1;
26 
27     for(int i = 1;i <= g;i++){
28         for(int j = 1;j <= MAXN;j++){
29             if(dp[i-1][j]){
30                 for(int k = 1;k <= c;k++){
31                     dp[i][j + a[k]*b[i]] += dp[i-1][j];
32                 }
33             }
34         }
35     }
36     printf("%d\n",dp[g][MAXN>>1]);
37 }
View Code

 POJ 1948 

http://poj.org/problem?id=1948

最近POJ国内老抽风,国外就可以上去,哼

细节要注意比较多,WA了好几次

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <queue>
 6 #include <vector>
 7 #include <algorithm>
 8 
 9 #define rep(i,a,n) for(int i = a;i < n;i++)
10 #define per(i,n,a) for(int i = n-1;i >=a;i--)
11 #define pb push_back
12 #define VI vector<int>
13 #define QI queue<int>
14 
15 typedef long long ll;
16 
17 using namespace std;
18 
19 const int N = 40 + 5;
20 const int M = 800 + 5; 
21 
22 int n;
23 int a[N] = {};
24 bool dp[M][M] = {};
25 double half,sum;
26 
27 bool check(int a,int b,int c){
28     if(a + b <= c || a + c <= b || b + c <= a){
29         return false;
30     }
31     else{
32         return true;
33     }
34 }
35 
36 int main(){
37     while(~scanf("%d",&n)){
38         sum = 0.0;
39         rep(i,0,n){
40             scanf("%d",&a[i]);
41             sum += a[i];
42         }
43         half = sum / 2;
44         memset(dp,0,sizeof(dp));
45         dp[0][0] = true;
46         rep(i,0,n){
47             per(j,half+1,0){
48                 per(k,half+1,0){
49                     if(j >= a[i] && dp[j - a[i]][k]){
50                         dp[j][k] = true;
51                     }
52                     if(k >= a[i] && dp[j][k - a[i]]){
53                         dp[j][k] = true;
54                     }
55                 }
56             }
57         }
58         int maxn = 0;
59         rep(i,1,half){
60             rep(j,1,half){
61                 if(dp[i][j]){
62                     double r = sqrt(half*(half-i)*(half-j)*(half-(sum-i-j)))*100;
63                     maxn = (maxn<=(int)r?(int)r:maxn);
64                 }       
65             }
66         }
67         printf("%d\n",maxn==0?-1:maxn);
68     }
69     return 0;
70 }
View Code

 POJ 3903

http://poj.org/problem?id=3903

因为题目看不懂就去搜了题解,知道了最长上升子序列(http://baike.baidu.com/subview/770542/15946409.htm)是什么

有两种时间复杂度的算法。我故意测试了时间复杂度是O(n^2)的,果然超时了。算了一下,10^10次,早就超时了

这道题目还要用到二分,二分的时间复杂度是O(nlogn),算了一下大概是5*10^5次,在POJ是63MS,不算快差不多是这个速度。看到题目里还有人是0MS的,估计还有什么技巧

顺便记一下操作符>>的注意事项:>>的优先级比+的小

所以原来我想表达(x+y)>>1的意思的,我就错误地写成了x+(y-x)>>1,其实这句话结果就是y>>1,所以要写成x+(y-x)/2。

学C的时候基础没有打好,就变成了现在这个下场T_T

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <queue>
 6 #include <vector>
 7 #include <algorithm>
 8 
 9 #define rep(i,a,n) for(int i = a;i < n;i++)
10 #define per(i,n,a) for(int i = n-1;i >=a;i--)
11 #define pb push_back
12 #define VI vector<int>
13 #define QI queue<int>
14 
15 typedef long long ll;
16 
17 using namespace std;
18 
19 int n;
20 const int N = 100000 + 5;
21 int a[N] = {},dp[N] = {};
22  
23 int binary_search(int x,int y,int q){
24     while(x <= y){    
25         int mid = (x + y) >> 1;
26         //int mid = x + (y - x)>>1;
27         //int mid = x + (y - x)/2;
28         if(dp[mid] >= q){
29             y = mid - 1;
30         }
31         else{
32             x = mid + 1;
33         }
34     }
35     return x;
36 }
37  
38 int main(){
39     while(~scanf("%d",&n)){
40         rep(i,0,n){
41             scanf("%d",&a[i]);
42         }
43         rep(i,0,n){
44             dp[i] = 0;
45         }
46         int len = 0;
47         rep(i,0,n){
48             if(dp[len] < a[i]){
49                 dp[++len] = a[i];
50             }
51             else{
52                 int j = binary_search(0,len,a[i]);
53                 dp[j] = a[i];
54             }
55         }
56         printf("%d\n",len);
57     }    
58     return 0;
59 }
View Code

 HDU 1203

http://acm.hdu.edu.cn/showproblem.php?pid=1203

水题,本来没怎么考虑空间复杂度,MLE了一次。

然后后来忘记每次都要memset,贡献了一次WA

最重要的是:你有1亿美元你还愁读什么学校?!直接哈佛啊?!你还读什么书?!

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <queue>
 6 #include <vector>
 7 #include <algorithm>
 8 
 9 #define rep(i,a,n) for(int i = a;i < n;i++)
10 #define per(i,n,a) for(int i = n-1;i >=a;i--)
11 #define pb push_back
12 #define VI vector<int>
13 #define QI queue<int>
14 
15 typedef long long ll;
16 
17 using namespace std;
18 
19 int n,m;
20 const int N  = 10000 + 5;
21 int a[N] = {};
22 double b[N] = {};
23 double dp[N] = {};
24 
25 int main(){
26     while(~scanf("%d%d",&n,&m),n+m > 0){
27         rep(i,0,m){
28             scanf("%d%lf",&a[i],&b[i]);
29         }
30         memset(dp,0.0,sizeof(dp));
31         rep(i,1,m+1){
32             per(j,n+1,a[i-1]){
33                 dp[j] = max(dp[j],1-((1-dp[j-a[i-1]])*(1-b[i-1])));
34             }
35         }
36         /*
37         rep(i,0,m+1){
38             rep(j,0,n+1){
39                 cout<<dp[i][j]<<i<<" "<<j<<" ";
40             }puts("");
41         }
42         */
43     printf("%.1f%%\n",dp[n]*100.0);
44     }
45     return 0;
46 }
View Code

 HDU 2955

http://acm.hdu.edu.cn/showproblem.php?pid=2955

这道题目因为本人的猪脑,认为把被抓住率加起来就可以了。无限WA

后来看了别人题解才知道是逃脱率乘起来

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <queue>
 6 #include <vector>
 7 #include <algorithm>
 8 
 9 #define rep(i,a,n) for(int i = a;i < n;i++)
10 #define per(i,n,a) for(int i = n-1;i >=a;i--)
11 #define pb push_back
12 #define VI vector<int>
13 #define QI queue<int>
14 
15 typedef long long ll;
16 
17 using namespace std;
18 
19 const int N = 100 + 5;
20 int t;
21 double n;
22 int a[N] = {};
23 double b[N] = {};
24 double dp[N*100] = {};
25 
26 int main(){
27     int T;
28     scanf("%d",&T);
29     while(T--){
30         scanf("%lf%d",&n,&t);
31         int sum = 0;
32         rep(i,0,t){
33             scanf("%d%lf",&a[i],&b[i]);
34             sum += a[i];
35         }
36         memset(dp,0,sizeof(dp));
37         dp[0] = 1;
38         rep(i,0,t+1){
39                 per(j,sum+1,a[i-1]){   
40                     dp[j] = max(dp[j],dp[j - a[i-1]]*(1-b[i-1]));
41                 }
42         }
43         per(i,sum+1,0){
44             if((1-n) <= dp[i]){
45                 cout<<i<<endl;
46                 break;
47             }
48         }
49     }    
50     return 0;
51 }
View Code

 HDU 2456

http://acm.hdu.edu.cn/showproblem.php?pid=2546

关键在于要把最贵的东西留到最后买,买到快只剩下5块的时候,再买最贵的直接刷爆

真是的这么邪恶的想法对于纯洁的我来说真的太污了!

超详细题解:http://blog.csdn.net/mengxiang000000/article/details/50365081

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <queue>
 6 #include <vector>
 7 #include <algorithm>
 8 
 9 #define rep(i,a,n) for(int i = a;i < n;i++)
10 #define per(i,n,a) for(int i = n-1;i >=a;i--)
11 #define pb push_back
12 #define VI vector<int>
13 #define QI queue<int>
14 
15 typedef long long ll;
16 
17 using namespace std;
18 
19 const int N = 1000 + 5;
20 int n,m;
21 int a[N] = {};
22 int dp[50000 + 5] = {};
23 
24 bool cmp(int a,int b){
25     return a < b;
26 }
27 
28 int main(){
29     while(~scanf("%d",&n),n>0){
30         int sum = 0;
31         rep(i,0,n){
32             scanf("%d",&a[i]);
33             sum += a[i];
34         }
35         sort(a,a+n,cmp);
36 
37         scanf("%d",&m);
38         if(m < 5){
39             printf("%d\n",m);
40             continue;
41         }
42         memset(dp,0,sizeof(dp));
43         rep(i,0,n){
44             per(j,m+1-5,a[i-1]){
45                 dp[j] = max(dp[j],dp[j - a[i-1]] + a[i-1]);
46             }
47         }
48         printf("%d\n",m-dp[m-5]-a[n-1]);
49     } 
50     return 0;
51 }
View Code

这些就是最近做的背包问题啦~下面就要(被)尿 并查集&最小生成树,区间dp就留在后面再来巩固一下。然后估计过完年,准备准备邻接表和哈希表差不多了。

背包问题链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=103972#overview

以上。

 

你可能感兴趣的:(寒假集训之 背包问题)