队友的建议,让我去学一学kuangbin的基础dp,在这里小小的整理总结一下吧。

  首先我感觉自己还远远不够称为一个dp选手,一是这些题目还远不够,二是定义状态的经验不足。不过这些题目让我在一定程度上加深了对dp的理解,但要想搞好dp,还需要多多练习啊。

  HDU - 1024 开场高能

  给出一个数列,分成m段,求这m段的和的最大值,dp[i][j]表示遍历到第i个数,已经划分了j段,对于每一个数有两种决策,加入上一个区间段,自己成为一个区间段,故dp[i][j] = max(dp[i-1][j]+a[i],dp[k][j-1]+a[i])     1<=k<=i-1,二维数组肯定不能开,所以使用两个数组,另一个数组保存上一次的状态,这样也可以及时的获得第二种情况的答案,然后再更新一遍旧状态就可以。一开始因为初始化问题错了几次。

  

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<vector>
  5. using namespace std;
  6. const int N = 1e6+;
  7. const int INF = 1e9;
  8. #define LL long long
  9. LL dp1[N],dp2[N];
  10. LL a[N];
  11. int main() {
  12. int n,m;
  13. while(~scanf("%d%d",&m,&n)) {
  14. for(int i=; i <=n; i++) {
  15. scanf("%lld",&a[i]);
  16. dp1[i] = dp2[i] = ;
  17. }
  18. dp1[] = ;
  19. dp2[] = ;
  20. for(int i =; i <= m; i++) {
  21. LL Max = -INF;
  22. for(int j=i; j <= n; j++) {
  23. Max = max(Max,dp2[j-]);
  24. dp1[j] = max(dp1[j-]+a[j],Max+a[j]);
  25. }
  26. for(int j =i; j <= n; j++) {
  27. dp2[j] = dp1[j];
  28. }
  29. }
  30. LL ans = -INF;
  31. for(int i = m; i <= n; i++) {
  32. ans = max(ans,dp1[i]);
  33. }
  34. printf("%lld\n",ans);
  35. }
  36. return ;
  37. }

  HDU - 1029 感觉跟dp没啥关系

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. const int N = 1e6+;
  7. #define LL long long
  8. LL a[N];
  9. int main(){
  10. int n;
  11. while(~scanf("%d",&n)){
  12. for(int i = ;i < n;i++){
  13. scanf("%lld",&a[i]);
  14. }
  15. sort(a,a+n);
  16. printf("%lld\n",a[n/]);
  17. }
  18. return ;
  19. }

  HDU - 1069 线性dp,排序后求最大权值

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. struct Rec{
  7. int c,k,g;
  8. }r[];
  9. void setRec(int id,int x,int y,int z){
  10. r[id].c = x;
  11. r[id].k = y;
  12. r[id].g = z;
  13. }
  14. int dp[];
  15. bool ok(int i,int j){
  16. if(r[i].c<r[j].c && r[i].k<r[j].k) return true;
  17. if(r[i].c<r[j].k && r[i].k<r[j].c) return true;
  18. return false;
  19. }
  20. bool cmp(Rec a,Rec b){
  21. return (a.c*a.k > b.c*b.k);
  22. }
  23. int main()
  24. {
  25. int n,x,y,z,ca=;
  26. while(~scanf("%d",&n)){
  27. if(!n) break;
  28. for(int i = ;i <= *n;i += ){
  29. scanf("%d%d%d",&x,&y,&z);
  30. setRec(i,x,y,z);
  31. setRec(i+,x,z,y);
  32. setRec(i+,y,z,x);
  33. }
  34. n = n*;
  35. sort(r+,r+n+,cmp);
  36. for(int i=;i <= n;i++){
  37. // cout<<r[i].c<<" "<<r[i].k<<" "<<r[i].g<<endl;
  38. dp[i] = r[i].g;
  39. for(int j = ;j < i;j++){
  40. if(ok(i,j)){
  41. dp[i] = max(dp[i],dp[j]+r[i].g);
  42. }
  43. }
  44. }
  45. int ans = ;
  46. for(int i = ;i <= n;i++){
  47. ans = max(ans,dp[i]);
  48. }
  49. printf("Case %d: maximum height = %d\n",++ca,ans);
  50. }
  51. }

  HDU - 1074  之前就做过,但基础dp里居然有状态压缩,因为这里只是求做作业的顺序,从小到大枚举所有状态,对于每一个状态,添加一个作业递推出新的状态,如果一个状态可以由多个途径达到,选择一个最优的,当所有作业选完以后就是答案,回溯状态输出一下就可以。

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. #define N 15
  7. #define M (1<<N)+N
  8. const int INF = 1e9;
  9. struct DP {
  10. int day,red,fa;
  11. } dp[M];
  12. struct Course {
  13. string name;
  14. int dl,cost;
  15. } c[N];
  16. void outPut(int k,int n) {
  17. int f = dp[k].fa;
  18. if(f == -) return;
  19. outPut(f,n);
  20. for(int i =; i < n; i++) {
  21. if((k&(<<i))!= && (f&(<<i))==) {
  22. cout<<c[i].name<<endl;
  23. break;
  24. }
  25. }
  26. }
  27. int main() {
  28. int T,n,day;
  29. scanf("%d",&T);
  30. while(T--) {
  31. scanf("%d",&n);
  32. for(int i = ; i < n; i++) {
  33. cin>>c[i].name>>c[i].dl>>c[i].cost;
  34. }
  35. int up = (<<n);
  36. for(int i = ; i < up; i++) {
  37. dp[i].fa = -;
  38. }
  39. dp[].day = dp[].red = ;
  40. for(int i=; i < up; i++) {
  41. for(int j=; j<n; j++) {
  42. if((i&(<<j)) == ) {
  43. int k = (i|(<<j));
  44. int nday = dp[i].day+c[j].cost;
  45. dp[k].day = nday;
  46. int nred = max(,nday-c[j].dl);
  47. if(dp[k].fa == -) {
  48. dp[k].red = dp[i].red+nred;
  49. dp[k].fa = i;
  50. } else if(dp[k].red > dp[i].red+nred) {
  51. dp[k].red = dp[i].red+nred;
  52. dp[k].fa = i;
  53. }
  54. }
  55. }
  56. }
  57. printf("%d\n",dp[up-].red);
  58. outPut(up-,n);
  59. }
  60. return ;
  61. }

  HDU - 1087 最长递增子序列

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. #define LL long long
  7. #define N 1005
  8. const int INF = 1e9;
  9. LL dp[N],a[N];
  10. int main()
  11. {
  12. int n;
  13. while(~scanf("%d",&n)){
  14. if(!n) break;
  15. LL ans = -INF;
  16. for(int i = ;i < n;i++){
  17. scanf("%lld",&a[i]);
  18. dp[i] = a[i];
  19. for(int j = ;j < i;j++){
  20. if(a[i]>a[j]) dp[i] = max(dp[i],dp[j]+a[i]);
  21. }
  22. ans = max(ans,dp[i]);
  23. }
  24. printf("%lld\n",ans);
  25. }
  26. return ;
  27. }

  HDU - 1114 完全背包,恰好装满,一开始初始化-1为不可达状态,状态转移的时候判断一下不可达状态就可以

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. const int N = ;
  7. const int M = ;
  8. int dp[N];
  9. struct Thing{
  10. int p,w;
  11. }t[M];
  12. int main()
  13. {
  14. int T,E,F,n;
  15. scanf("%d",&T);
  16. while(T--){
  17. scanf("%d%d",&E,&F);
  18. int all = F-E;
  19. scanf("%d",&n);
  20. for(int i = ;i <n;i++){
  21. scanf("%d %d",&t[i].p,&t[i].w);
  22. }
  23. memset(dp,-,sizeof(dp));
  24. dp[] = ;
  25. for(int i = ;i < n;i++){
  26. for(int j =t[i].w; j<= all;j++){
  27. int Last = j-t[i].w;
  28. if(dp[Last] == -) continue;
  29. if(dp[j]==-) dp[j] = dp[Last]+t[i].p;
  30. else dp[j] = min(dp[j],dp[Last]+t[i].p);
  31. }
  32. }
  33. if(dp[all] == -){
  34. printf("This is impossible.\n");
  35. }else printf("The minimum amount of money in the piggy-bank is %d.\n",dp[all]);
  36. }
  37. return ;
  38. }

  HDU - 1176 数塔,倒着算

  

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. #define N 100005
  7. int dp[][N],a[][N];
  8. int main()
  9. {
  10. int n,t,x,Mt;
  11. while(~scanf("%d",&n)){
  12. if(!n) break;
  13. memset(a,,sizeof(a));
  14. Mt = ;
  15. for(int i=;i<n;i++){
  16. scanf("%d%d",&x,&t);
  17. a[x][t]++;
  18. Mt = max(Mt,t);
  19. }
  20. for(int i=;i<=;i++){
  21. dp[i][Mt+] = ;
  22. }
  23. for(int i=Mt;i>=;i--){
  24. for(int j=;j <= ;j++){
  25. int Max = -;
  26. if(j==) Max = max(dp[j][i+],dp[j+][i+]);
  27. else if(j==) Max = max(dp[j][i+],dp[j-][i+]);
  28. else Max = max(max(dp[j][i+],dp[j+][i+]),dp[j-][i+]);
  29. dp[j][i] = Max + a[j][i];
  30. }
  31. }
  32. printf("%d\n",dp[][]);
  33. }
  34. return ;
  35. }

  HDU - 1260  基础dp,12点的时候算am,还是pm呢。。题目中都没有这组样例,我还困惑了一会

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. #define N 2005
  7. int a[N],b[N],dp[N];
  8. int main() {
  9. int T,n;
  10. scanf("%d",&T);
  11. while(T--) {
  12. scanf("%d",&n);
  13. for(int i=; i<=n; i++) {
  14. scanf("%d",&a[i]);
  15. }
  16. for(int i=; i<=n; i++) {
  17. scanf("%d",&b[i]);
  18. }
  19. dp[] = ;
  20. for(int i=; i<=n; i++) {
  21. if(i==) dp[i] = a[i];
  22. else dp[i] = min(dp[i-]+a[i],dp[i-]+b[i]);
  23. }
  24. int tmp = dp[n];
  25. int s = tmp%;
  26. tmp /= ;
  27. int m = tmp%;
  28. tmp /= ;
  29. int h = tmp%+;
  30. h %= ;
  31. bool f = true;
  32. if(h == ) f = false;
  33. if(h > ) {
  34. h -= ;
  35. }
  36. printf("%02d:%02d:%02d ",h,m,s);
  37. if(f) printf("am\n");
  38. else printf("pm\n");
  39. }
  40. return ;
  41. }

  HDU - 1257  这个题目是有争议的,但是我认为这个题目就是让求,将此序列划分为最长递减序列的最少条数,dp[i]代表第i个子序列的最小值,一个数的决策,当然是加入到距离dp[i]最小的那一个,这样能保证条数最少,而这样做正好就对应了kuangbin的贪心代码

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. const int N = 1e6;
  7. const int INF = 1e9;
  8. int dp[N]; ///dp[i]表示第i个子序列的最小值
  9. int main()
  10. {
  11. int n,m,tmp;
  12. while(~scanf("%d",&n)){
  13. m = ;
  14. for(int i=;i<n;i++){
  15. scanf("%d",&tmp);
  16. int Min = INF,End=-;
  17. for(int j =;j < m;j++){
  18. if(tmp<=dp[j] && dp[j]-tmp < Min){
  19. Min = min(Min,dp[j]-tmp);
  20. End = j;
  21. }
  22. }
  23. if(End == -) dp[m++] = tmp;
  24. else dp[End] = tmp;
  25. }
  26. printf("%d\n",m);
  27. }
  28. return ;
  29. }

  HDU - 1160

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. const int N = ;
  7. const int INF = 1e9;
  8. struct DP{
  9. int len,pre;
  10. }dp[N];
  11. struct Mice{
  12. int w,s,id;
  13. }m[N];
  14. bool cmp(Mice a,Mice b){
  15. if(a.w != b.w) return a.w < b.w;
  16. else return a.s < b.s;
  17. }
  18. int Stack[N];
  19. int main()
  20. {
  21. // freopen("in.cpp","r",stdin);
  22. int tot=;
  23. while(scanf("%d %d",&m[tot].w,&m[tot].s) != EOF){
  24. m[tot].id = tot;
  25. tot++;
  26. }
  27. sort(m,m+tot,cmp);
  28. for(int i =;i < tot;i++){
  29. dp[i].len = ;
  30. dp[i].pre = -;
  31. for(int j=;j<i;j++){
  32. if(m[i].w>m[j].w && m[i].s<m[j].s){
  33. if(dp[i].len < dp[j].len+){
  34. dp[i].len = dp[j].len+;
  35. dp[i].pre = j;
  36. }
  37. }
  38. }
  39. }
  40. int Max = -INF,End=-;
  41. for(int i=;i<tot;i++){
  42. if(dp[i].len > Max){
  43. Max = dp[i].len;
  44. End = i;
  45. }
  46. }
  47. printf("%d\n",Max);
  48. int top=;
  49. while(End != -){
  50. Stack[top++] = m[End].id+;
  51. End = dp[End].pre;
  52. }
  53. while(top != ){
  54. printf("%d\n",Stack[--top]);
  55. }
  56. return ;
  57. }

  POJ - 1015 这里面我感觉这个题是很难的了,因为我没有找到状态的正确定义,原来是dp[i][k]代表已经选出i个人,差为k的最大和,使用path记录每个状态的决策,在选人的时候通过回溯判断这个人是否已经被选过,我一开始用的vis,各种wa,还没有明白是怎么回事,一开始平移区间还移出了毛病。。

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. const int N = ;
  7. const int INF = 1e9;
  8. int dp[][],path[][];
  9. int cha[N],he[N],x[N],y[N],n,m;
  10. ///使用path记录此状态选的是哪一个人
  11. bool ok(int i,int j,int k) {
  12. while(i> && path[i][j] != -) {
  13. if(path[i][j] == k) return false;
  14. j -= cha[path[i][j]];
  15. i--;
  16. }
  17. return true;
  18. }
  19. int out[N],os,p,d;
  20. void Print(int i,int j) {
  21. os = p = d = ;
  22. while(i> && path[i][j] != -) {
  23. int k = path[i][j];
  24. j -= cha[k];
  25. i--;
  26. out[os++] = k;
  27. p += x[k];
  28. d += y[k];
  29. }
  30. }
  31. int main() {
  32. int ca=;
  33. while(~scanf("%d%d",&n,&m)) {
  34. if(n== && m==) break;
  35. for(int i = ; i <= n; i++) {
  36. scanf("%d%d",&x[i],&y[i]);
  37. cha[i] = x[i]-y[i];
  38. he[i] = y[i]+x[i];
  39. }
  40. memset(dp,-,sizeof(dp));
  41. memset(path,-,sizeof(path));
  42. int km = m*;
  43. dp[][km] = ;
  44. for(int i=; i<m; i++) {
  45. for(int j=; j<=*km; j++) {
  46. if(dp[i][j] == -) continue;
  47. for(int k=; k<=n; k++) {
  48. int nj = j+cha[k];
  49. if(!ok(i,j,k)) continue;
  50. if(dp[i+][nj]<dp[i][j]+he[k]) {
  51. dp[i+][nj] = dp[i][j] + he[k];
  52. path[i+][nj] = k;
  53. }
  54. }
  55. }
  56. }
  57. int Min = INF,End=-,Max = -INF;
  58. for(int i = ; i <= *km; i++) {
  59. if(dp[m][i]!=-) {
  60. if(abs(i-km)<Min) {
  61. Min = abs(i-km);
  62. End = i;
  63. Max = dp[m][i];
  64. } else if(abs(i-km) == Min&&dp[m][i]>Max) {
  65. End = i;
  66. Max = dp[m][i];
  67. }
  68. }
  69. }
  70. printf("Jury #%d\n",++ca);
  71. Print(m,End);
  72. printf("Best jury has value %d for prosecution and value %d for defence:\n",p,d);
  73. sort(out,out+os);
  74. for(int i = ; i < os; i++) {
  75. printf(" %d",out[i]);
  76. }
  77. printf("\n\n");
  78. }
  79. return ;
  80. }

  POJ - 1458 最长公共子串

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. const int N = 1e3 + ;
  7. const int INF = 1e9;
  8. char a[N],b[N];
  9. int dp[N][N];
  10. int main()
  11. {
  12. while(~scanf("%s%s",a+,b+)){
  13. int lena = strlen(a+);
  14. int lenb = strlen(b+);
  15. memset(dp,,sizeof(dp));
  16. for(int i = ;i <= lena;i++){
  17. for(int j=;j <= lenb;j++){
  18. if(i==||j==) dp[i][j] = ;
  19. else{
  20. if(a[i]==b[j]) dp[i][j] = dp[i-][j-]+;
  21. dp[i][j]=max(dp[i][j],max(dp[i-][j],dp[i][j-]));
  22. }
  23. }
  24. }
  25. printf("%d\n",dp[lena][lenb]);
  26. }
  27. return ;
  28. }

  POJ - 1661 它只能从板的两边下落这是最重要的,dp[i][2]代表从第i个板子的左边或者右边掉到地上所需的最少时间,然后这就变成了线性dp,正常转移即可,然后有几个小坑,比如有可能直接落到地上,一开始忘记考虑这个wa了一发

  POJ - 2533 最长递增子序列

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. const int N = 1e3 + ;
  7. const int INF = 1e9;
  8. int dp[N],a[N];
  9. int main()
  10. {
  11. int n,ans;
  12. while(~scanf("%d",&n)){
  13. ans = -INF;
  14. for(int i = ;i < n;i++){
  15. scanf("%d",&a[i]);
  16. dp[i] = ;
  17. for(int j=;j<i;j++){
  18. if(a[i]>a[j]){
  19. dp[i] = max(dp[i],dp[j]+);
  20. }
  21. }
  22. ans = max(ans,dp[i]);
  23. }
  24. printf("%d\n",ans);
  25. }
  26. }

  POJ - 3186  因为只能从最上面和最下面选数,所以可以定义状态,dp[i][j]表示从i到j还没有被选出所能到达的最大值

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. const int N = 2e3 + ;
  7. const int INF = 1e9;
  8. int dp[N][N],a[N];
  9. int main()
  10. {
  11. int n;
  12. while(~scanf("%d",&n)){
  13. for(int i=;i<=n;i++){
  14. scanf("%d",&a[i]);
  15. }
  16. memset(dp,,sizeof(dp));
  17. for(int i=;i<=n;i++){
  18. for(int j=n;j>=i;j--){
  19. int nd = n-(j-i+);
  20. if(i== && j==n) continue;
  21. if(j!=n) dp[i][j]=max(dp[i][j],dp[i][j+]+a[j+]*nd);
  22. if(i!=) dp[i][j]=max(dp[i][j],dp[i-][j]+a[i-]*nd);
  23. }
  24. }
  25. int ans = -INF;
  26. for(int i=;i<=n;i++){
  27. ans = max(ans,dp[i][i]+a[i]*n);
  28. }
  29. printf("%d\n",ans);
  30. }
  31. return ;
  32. }

  HDU - 1078 记忆化搜索,一开始读错了题,以为k步可以拐弯,想复杂了

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. #include<queue>
  6. using namespace std;
  7. const int N = ;
  8. const int INF = 1e9;
  9. int dp[N][N],n,k;
  10. int mp[N][N],go[][]= {,,-,,,-,,};
  11. bool inMap(int x,int y) {
  12. return (x>=&&x<n&&y>=&&y<n);
  13. }
  14. int dfs(int x,int y) {
  15. if(dp[x][y] != -) return dp[x][y];
  16. int Max = ,nx,ny;
  17. for(int j =; j<=k; j++) {
  18. for(int i = ; i < ; i++) {
  19. nx = x + go[i][]*j;
  20. ny = y + go[i][]*j;
  21. if(inMap(nx,ny) && mp[nx][ny] > mp[x][y]) {
  22. Max = max(Max,dfs(nx,ny));
  23. }
  24. }
  25. }
  26. return dp[x][y] = mp[x][y] + Max;
  27. }
  28. int main() {
  29. while(~scanf("%d%d",&n,&k)) {
  30. if(n==- && k==-) break;
  31. for(int i=; i<n; i++) {
  32. for(int j=; j<n; j++) {
  33. scanf("%d",&mp[i][j]);
  34. }
  35. }
  36. memset(dp,-,sizeof(dp));
  37. int ans = dfs(,);
  38. printf("%d\n",ans);
  39. }
  40. return ;
  41. }

  HDU - 2859 挺巧妙的题,沿着对角线扩展,dp[i][j]表示以(i,j)位置为右上角所能形成的最大对称矩阵,转移状态的时候需要注意,dp[i-1][j+1]如果大于上一个状态,直接由上一个状态加1,如果小于等于上一个状态,那么就等于延伸的最大长度,他的正确性由前一个状态保证

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. #include<queue>
  6. using namespace std;
  7. const int N = ;
  8. const int INF = 1e9;
  9. char mp[N][N];
  10. int dp[N][N];
  11. int main()
  12. {
  13. int n,ans;
  14. while(~scanf("%d",&n)){
  15. if(n==) break;
  16. for(int i=;i<=n;i++){
  17. scanf("%s",mp[i]+);
  18. }
  19. for(int i=;i<=n;i++){
  20. dp[i][] = dp[n][i] = ;
  21. }
  22. ans = ;
  23. for(int i=n-;i>=;i--){
  24. for(int j=;j<=n;j++){
  25. int len = ;
  26. while(j-len>=&&i+len<=n && mp[i+len][j]==mp[i][j-len]){
  27. len++;
  28. }
  29. // cout<<mp[i][j]<<" len = "<<len<<endl;
  30. if(len >= dp[i+][j-]+) {
  31. dp[i][j] = dp[i+][j-]+;
  32. }else dp[i][j] = len;
  33. ans = max(ans,dp[i][j]);
  34. }
  35. }
  36. printf("%d\n",ans);
  37. }
  38. return ;
  39. }

  POJ - 3616 被这个题晃了一下,本来就是个线性dp,跟n没关系

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. #include<queue>
  6. using namespace std;
  7. const int N = 1e3+;
  8. const int INF = 1e9;
  9. int dp[N];
  10. struct Thing{
  11. int l,r,w;
  12. }t[N];
  13. bool cmp(Thing a,Thing b){
  14. if(a.l != b.l) return a.l < b.l;
  15. return a.r < b.r;
  16. }
  17. int main()
  18. {
  19. int n,m,r,ans;
  20. while(~scanf("%d%d%d",&n,&m,&r)){
  21. for(int i=;i<=m;i++){
  22. scanf("%d%d%d",&t[i].l,&t[i].r,&t[i].w);
  23. }
  24. ans = -INF;
  25. sort(t+,t++m,cmp);
  26. for(int i=;i<=m;i++){
  27. dp[i] = t[i].w;
  28. for(int j=;j < i;j++){
  29. if(t[i].l >= t[j].r+r){
  30. dp[i] = max(dp[i],dp[j]+t[i].w);
  31. }
  32. }
  33. ans = max(ans,dp[i]);
  34. }
  35. printf("%d\n",ans);
  36. }
  37. return ;
  38. }

  POJ - 3666 将一个序列修改为有序序列的最小花费,对于一个长度为n的序列,如果将他改成非递减的序列,那么可以证明最后一个数可以是这个序列的最大值,而不影响答案,对n+1的序列也是如此,归纳知最终序列中的数可以全部来自原先序列,定义dp[i][j]为选到第i个数,最后一个数为有序序列的第j个数的最小值,滚动数组,枚举上一个状态的结尾数,之所以要排序是因为要保证这个序列的有序性,正序倒序分别求一次就可以得到最优解。

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. #include<queue>
  6. using namespace std;
  7. const int N = ;
  8. const int INF = 1e9;
  9. int a[N],dp[N],n,b[N];
  10. int fun1(){
  11. sort(b+,b++n);
  12. memset(dp,,sizeof(dp));
  13. for(int i=;i<=n;i++){
  14. int Min = INF;
  15. for(int j=;j<=n;j++){
  16. Min = min(Min,dp[j]);
  17. dp[j] = Min+abs(a[i]-b[j]);
  18. }
  19. }
  20. int res = INF;
  21. for(int i=;i<=n;i++){
  22. res = min(res,dp[i]);
  23. }
  24. return res;
  25. }
  26. bool cmp(int a,int b){
  27. return a > b;
  28. }
  29. int fun2(){
  30. sort(b+,b++n,cmp);
  31. memset(dp,,sizeof(dp));
  32. for(int i=;i<=n;i++){
  33. int Min = INF;
  34. for(int j=;j<=n;j++){
  35. Min = min(Min,dp[j]);
  36. dp[j] = Min+abs(a[i]-b[j]);
  37. }
  38. }
  39. int res = INF;
  40. for(int i=;i<=n;i++){
  41. res = min(res,dp[i]);
  42. }
  43. return res;
  44. }
  45. int main() {
  46. int ans;
  47. while(~scanf("%d",&n)) {
  48. for(int i=; i<=n; i++) {
  49. scanf("%d",&a[i]);
  50. b[i] = a[i];
  51. }
  52. ans = min(fun1(),fun2());
  53. printf("%d\n",ans);
  54. }
  55. return ;
  56. }

  

基础dp的更多相关文章

  1. 基础DP(初级版)

    本文主要内容为基础DP,内容来源为<算法导论>,总结不易,转载请注明出处. 后续会更新出kuanbin关于基础DP的题目...... 动态规划: 动态规划用于子问题重叠的情况,即不同的子问 ...

  2. hdu 5586 Sum 基础dp

    Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Desc ...

  3. hdu 4055 Number String (基础dp)

    Number String Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  4. 训练指南 UVA - 10917(最短路Dijkstra + 基础DP)

    layout: post title: 训练指南 UVA - 10917(最短路Dijkstra + 基础DP) author: "luowentaoaa" catalog: tr ...

  5. 训练指南 UVA - 11324(双连通分量 + 缩点+ 基础DP)

    layout: post title: 训练指南 UVA - 11324(双连通分量 + 缩点+ 基础DP) author: "luowentaoaa" catalog: true ...

  6. 「kuangbin带你飞」专题十二 基础DP

    layout: post title: 「kuangbin带你飞」专题十二 基础DP author: "luowentaoaa" catalog: true tags: mathj ...

  7. M - 基础DP

    M - 基础DP Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Descriptio ...

  8. lightoj1004【基础DP】

    从低端到顶端求个最大值: 思路: 基础DP,递推 #include<cstdio> #include<queue> #include<map> #include&l ...

  9. hdu 4489 The King’s Ups and Downs(基础dp)

    The King’s Ups and Downs Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java ...

随机推荐

  1. VS2012下基于Glut OpenGL glDepthMask示例程序:

    glDepthMask (GLboolean flag)函数可以决定将他之后的数据不写入深度缓冲区.当flag为GL_TRUE时之后的数据不写入深度缓冲区,即使启用了深度缓冲区测试功能. 使用上一个D ...

  2. Js-Html 前端系列--显示有格式的文本

    var dp = $("#dp").val(); var dpXSS = filterXss(dp); document.getElementById("descript ...

  3. PHP里文件的查找方式及写法

    PHP里说的文件包括:文件和目录1.用filetype方法加路径("./11.txt")是判断文件类型 //var_dump(filetype("./11.txt&quo ...

  4. 使用div模拟textarea,实现文本输入框高度自适应(附:js控制textarea实现文本输入框高度自适应)

    一.使用textarea标签进行多行文本的输入有很多限制,比如不能实现高度自适应,会出现难看的滚动条等问题. HTML5中添加了一个新属性contenteditable,该属性可以让input,tex ...

  5. 用linux 命令 执行ci框架的方法

    最近要跑一个数据量比较大的脚本,刚开始在浏览器页面访问发行nginx 5.4 超时, 又不想去修改nginx的连接时间,只能在服务器执行了, 执行方法:进入到ci 的根目录:#php index.ph ...

  6. 认识div在排版中的作用

    在网页制作过程过中,可以把一些独立的逻辑部分划分出来,放在一个<div>标签中,这个<div>标签的作用就相当于一个容器. 语法: <div>-</div&g ...

  7. Hadoop基本命令详解

    调用文件系统(FS)Shell命令应使用bin/hadoop fs <args>的形式.所有的的FS shell命令使用URI路径作为参数.URI路径详解点击这里. 1.cat 说明:将路 ...

  8. 原生js

  9. iOS 自定义layer的两种方式

    在iOS中,你能看得见摸得着的东西基本都是UIView,比如一个按钮,一个标签,一个文本输入框,这些都是UIView: 其实UIView之所以能显示在屏幕上,完全是因为它内部的一个图层 在创建UIVi ...

  10. 关于web多标签多条件筛选的思考以及缓存的正确使用方法(上)

    做项目的过程中,发现一次远程链接数据库的耗时大概是300ms~400ms,切身体会到了前辈们经常说的减少链接的重要性,用了缓存后页面的打开时间从1.5s减少到400ms 前提: 那么来说一说正题,we ...