每日一题(11): poj1276
来源:互联网 发布:ubuntu 访问网络命令 编辑:程序博客网 时间:2024/06/14 13:23
1. 本来觉得很简单,却耗费了一天半的时间。本来做完1837之后感觉已经明白了怎么做。但是事实仿佛并非如此。当然,这也有自己的一点执念。
2. 这几天体会到,写程序就像做数学题一样,很忌讳一算就错。程序也是,不能想起来觉得这样这样,但是写起来没有把握对。就像前两天有个演讲说的那样,印度的程序很厉害,因为所有人写的都一样。程序是工业产品,流水线上的产品,是有标准答案的。
3. 总觉得不要怕。自己在这次中遇到了很严重的问题,不知道怎么错的。是自己的思路。要是以往,也许就是看看网上别人的思路,照着别人的思路写。这样,即使写不对还可以有答案看。但是这次自己逼着自己去一点一点思考,到底哪里有问题。程序就是这样,肯定是思路的不严谨。要勇敢,敢于啃硬骨头。一定要想明白。这对于上面的自信很重要。一定要将来,自己写的代码有把握不出错。
4. 说这道题,其实就是多重背包问题。背包九讲里面说的很好。就不多说了。只是我写了好几个版本,包括原始的,暴力,二进制优化的。
5.自己的版本一直过不了。因为超时。原来是因为有问题,自己思路错了。
8, 上面的代码进行空间优化:还是超时,测试案例都可以过,就是超时。根据和网上大家思路的比对,自己确实是最慢的。而且也没有想到怎么剪枝。
10. 多重背包的标准写法:
11. 这里总结一下背包问题的几个点,便于以后写。那就是首选空间优化过的,时间上优化过的。也就是最好的算。完全和01在第二层循环上不同。多重在输入上不同。还有,就是第一层循环的起始和终点一般没有可优化的地方。但是二层,可以。一般起始或者终点可以优化。而且,要注意顺序。还有就是dp[j]是等于或者加等于起始都可以。因为每个点都知访问一次。
2. 这几天体会到,写程序就像做数学题一样,很忌讳一算就错。程序也是,不能想起来觉得这样这样,但是写起来没有把握对。就像前两天有个演讲说的那样,印度的程序很厉害,因为所有人写的都一样。程序是工业产品,流水线上的产品,是有标准答案的。
3. 总觉得不要怕。自己在这次中遇到了很严重的问题,不知道怎么错的。是自己的思路。要是以往,也许就是看看网上别人的思路,照着别人的思路写。这样,即使写不对还可以有答案看。但是这次自己逼着自己去一点一点思考,到底哪里有问题。程序就是这样,肯定是思路的不严谨。要勇敢,敢于啃硬骨头。一定要想明白。这对于上面的自信很重要。一定要将来,自己写的代码有把握不出错。
4. 说这道题,其实就是多重背包问题。背包九讲里面说的很好。就不多说了。只是我写了好几个版本,包括原始的,暴力,二进制优化的。
5.自己的版本一直过不了。因为超时。原来是因为有问题,自己思路错了。
6. 这道题是多个测试案例。不要忘了。否则就是wa。但是题目里面没有
下面是各个版本的代码:
7. 首先是自己的思路,很基本的三层循环:
#include<iostream>#include<stdio.h>#include<string.h>using namespace std;int n;int c;int num[20];int cash[20];int dp[11][100005];int main(){//freopen("input.txt","r",stdin);while(~scanf("%d%d",&c,&n)){//cin>>c>>n;//这里其实可以不要。只是为了剪枝。for(int i = 1; i<=n; i++){cin>>num[i]>>cash[i];}if(n==0||c==0){cout <<0<<endl;continue;}memset(dp,0,sizeof(dp));for(int i = 1; i<=n; i++){for(int j = cash[i]; j<=c; j++){int temp=0;int flag = 0;for(int k = 0; k<=num[i]; k++){//在此处错了好久。因为temp是要取最大的。所以要加if来判断。if(j>=k*cash[i]){if(temp<dp[i-1][j-k*cash[i]] + k*cash[i])temp = dp[i-1][j-k*cash[i]] + k*cash[i];//flag=1;//break;}}//原来把这写到里面了。而且k没有去0,这样就麻烦了。if(temp>dp[i-1][j])dp[i][j] = temp;else dp[i][j] =dp[i-1][j];}}cout <<dp[n][c]<<endl;}}
8, 上面的代码进行空间优化:还是超时,测试案例都可以过,就是超时。根据和网上大家思路的比对,自己确实是最慢的。而且也没有想到怎么剪枝。
#include<iostream>#include<stdio.h>#include<string.h>using namespace std;int n;int c;int num[20];int cash[20];int dp[100005];int main(){//freopen("input.txt","r",stdin);//没有while是肯定错的。while(~scanf("%d%d",&c,&n)){//scanf("%d%d",&c,&n);for(int i = 1; i<=n; i++){cin>>num[i]>>cash[i];}//cout<<"test: "<<c<<","<<n<<endl;//cin>>c>>n;if(c==0){cout << 0<<endl;continue;}if(n==0){cout <<0<<endl;continue;}memset(dp,0,sizeof(dp));for(int i = 1; i<=n; i++){for(int j = c; j>=1; j--){int temp=0;//int flag = 0;for(int k = 0; k<=num[i]; k++){if(j>=k*cash[i]){if(temp<dp[j-k*cash[i]] + k*cash[i])temp = dp[j-k*cash[i]] + k*cash[i];//flag=1;//break;}//if(j+k*cash[i]>c) break;}if(temp>dp[j])dp[j] = temp;//cout<<"test:"<<dp[j]<<endl;//else dp[j] =dp[j];}}cout <<dp[c]<<endl;}}9. 在网上看到的暴力解法:
#include<iostream>#include<stdio.h>#include<string.h>using namespace std;int n;int c;int num[20];int cash[20];int dp[100005];int main(){//freopen("input.txt","r",stdin);while(~scanf("%d%d",&c,&n)){for(int i = 1; i<=n; i++){cin>>num[i]>>cash[i];}//cout<<"test: "<<c<<","<<n<<endl;//cin>>c>>n;if(c==0){cout << 0<<endl;continue;}if(n==0){cout <<0<<endl;continue;}memset(dp,0,sizeof(dp));int maxn = 0;dp[0] = 1;for(int i =1; i<=n;i++){//for(int j = maxn; j<=c; j++)//因为其他都是0//这里是可以用maxn的,其实其他的方法也可以。只是没有maxn,这里正好求出来了每次的最大值。另外,从现在的全部区间,求更大区间,应该可以理解。for(int j = maxn; j>=0; j--){if(dp[j]==1){for(int k = 1; k<=num[i]; k++){int temp = j+k*cash[i];if(temp>c)continue;dp[temp] = 1;if(temp>maxn)maxn = temp;}}}}cout <<maxn<<endl;}}
10. 多重背包的标准写法:
#include<iostream>#include<stdio.h>#include<string.h>using namespace std;int dp[100005];int cash[150];//int num[20];int c,n;int count;int main(){freopen("input.txt","r",stdin);while(~scanf("%d%d",&c,&n)){memset(dp,0,sizeof(dp));int numTemp,cashTemp;count = 1;for(int i = 1; i<=n; i++){cin>>numTemp>>cashTemp;if(numTemp==0) continue;cash[count] = cashTemp;count++;if(numTemp-1>0){int countTemp = numTemp-1;int k = 2;while(countTemp>0){countTemp = countTemp-k;//不能把这里的代码去掉。因为如果去掉了,总数会少if(countTemp<0){cash[count++] = cashTemp*(countTemp+k);break;}cash[count++] = cashTemp * k;k = k*2;}}}for(int i = 1; i <count; i++){for(int j = c; j >= 0; j--){if(j>=cash[i])if(dp[j-cash[i]]+cash[i]>dp[j])dp[j]=dp[j-cash[i]]+cash[i];}}cout<<dp[c]<<endl;}}
11. 这里总结一下背包问题的几个点,便于以后写。那就是首选空间优化过的,时间上优化过的。也就是最好的算。完全和01在第二层循环上不同。多重在输入上不同。还有,就是第一层循环的起始和终点一般没有可优化的地方。但是二层,可以。一般起始或者终点可以优化。而且,要注意顺序。还有就是dp[j]是等于或者加等于起始都可以。因为每个点都知访问一次。
12. 如果要记录路径的话,应该就可最大序列差不多了。
0 0
- 每日一题(11): poj1276
- 每日一题(一)
- 面试—每日一题(11)
- 每日一题 -- 11-1
- 每日一Vim(11)
- 每日一题(二)
- 每日一题(三)
- 每日一题(四)
- 每日一题(五)
- 每日一题(六)
- 每日一题(七)
- 每日一题(day1)
- 每日一题(day2)
- 每日一题(day3)
- 每日一题(day4)
- 每日一题(day5)
- 每日一题(1):
- 每日一题(2):
- Servlet基础
- Lesson1 初识HTML
- android手机各大分区详解
- Android Path的使用
- 用FTP传输做上传诊断
- 每日一题(11): poj1276
- qt使用ros库
- 进程之间的通信的方式有哪些,他们之间的区别是什么!或者是忧缺点
- 关于java中static一个有意思的小案例
- 多线程使用经验
- easyui点击添加行,动态增删改查
- IT人物之《Netty权威指南》中文作者 专访华为李林锋:我与Netty那些不得不说的事
- 第13周OJ练习-1 学生分数处理
- 什么是服务器池化