• 动态规划 dp


    1.洛谷 P1049 装箱问题

    题目描述

    有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30,每个物品有一个体积(正整数)。

    要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。

    输入输出格式

    输入格式:

    一个整数,表示箱子容量

    一个整数,表示有n个物品

    接下来n行,分别表示这n 个物品的各自体积

    输出格式:

    一个整数,表示箱子剩余空间。

    输入输出样例

    输入样例#1:
    24
    6
    8
    3
    12
    7
    9
    7
    
    输出样例#1:
    0
    

    说明

    NOIp2001普及组 第4题

    思路:

      f数组里记录的是最大能够存放的物体的体积,我们在输入的时候将每个物体的先在c数组中记录一下,(结合一下01背包,c数组就相当于每个物体的价值),那么同样对于每件物品我们还是有不放和放两种情况,所以转移方程就出来啦!!

       f[j] = max(f[j],f[j-vi[i]]+c[i]);

    (⊙v⊙)嗯~ 代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 
     5 long long V,n,vi[50];
     6 long long f[500000],c[50];
     7 
     8 int main() {
     9     cin>>V>>n;
    10     for(int i=1; i<=n ;i++) {
    11         cin>>vi[i];
    12         c[i]=vi[i];
    13     }
    14     for(int i=1; i<=n; i++) {
    15         for(int j=V; j>=vi[i]; j--) {
    16             f[j] = max(f[j],f[j-vi[i]]+c[i]);
    17         }
    18     }
    19     cout<<V-f[V]<<endl;
    20     return 0;
    21 }

    2.P1002 过河卒

    题目描述

    棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。

    棋盘用坐标表示,A点(0, 0)、B点(n, m)(n, m为不超过20的整数),同样马的位置坐标是需要给出的。

    现在要求你计算出卒从A点能够到达B点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。

    输入输出格式

    输入格式:

    一行四个数据,分别表示B点坐标和马的坐标。

    输出格式:

    一个数据,表示所有的路径条数。

    输入输出样例

    输入样例#1:
    6 6 3 3
    
    输出样例#1:
    6
    

    说明

    结果可能很大!

    思路:

      因为马所在点和马能够一步跳跃的点是不可以走的,所以要先开个数组标记一下,(大家肯定对dx,dy数组并不陌生,所以就不介绍啦~(≧▽≦)/~),因为从0开始会出现负数下标,所以我们从1开始,那么就将数组向右下移一格。因为卒只能往右或下跳,所以对于每个点都是由它上面的点或下面的点扩展来的,(加法原理),运用类似前缀和的做法,每个点上记录的是到达此点的路径条数,所以最后一个点上记录的就是从A到B的所有路径,输出就OK。。。

    (⊙v⊙)嗯~ 代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 
     5 const long long N = 2001;
     6 long long x,y,n,m,f[N][N],vis[N][N];
     7 int dx[9] = {0,2,-2,2,-2,1,-1,1,-1};
     8 int dy[9] = {0,1,1,-1,-1,2,2,-2,-2};
     9 
    10 int main() {
    11     cin>>n>>m>>x>>y;
    12     for(int i=0; i<=8; i++) {
    13         int xx=dx[i]+x,yy=dy[i]+y;
    14         if(xx>=0&&xx<=m&&yy>=0&&yy<=n) {
    15             vis[xx+1][yy+1]=1;
    16         }
    17     }
    18     f[1][1]=1;
    19     for(int i=1; i<=n+1; i++) {
    20         for(int j=1; j<=m+1; j++) {
    21             if(!vis[i][j]) {
    22                 f[i][j]+=f[i-1][j]+f[i][j-1];
    23             }
    24         }
    25     }
    26     cout<<f[n+1][m+1]<<endl;
    27     return 0;
    28 }

     3.P1004 方格取数

    题目描述

    设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放

    人数字0。如下图所示(见样例):

    A
     0  0  0  0  0  0  0  0
     0  0 13  0  0  6  0  0
     0  0  0  0  7  0  0  0
     0  0  0 14  0  0  0  0
     0 21  0  0  0  4  0  0
     0  0 15  0  0  0  0  0
     0 14  0  0  0  0  0  0
     0  0  0  0  0  0  0  0
    .                       B

    某人从图的左上角的A点出发,可以向下行走,也可以向右走,直到到达右下角的B

    点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。

    此人从A点到B点共走两次,试找出2条这样的路径,使得取得的数之和为最大。

    输入输出格式

    输入格式:

    输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个

    表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。

    输出格式:

    只需输出一个整数,表示2条路径上取得的最大的和。

    输入输出样例

    输入样例#1:
    8
    2 3 13
    2 6  6
    3 5  7
    4 4 14
    5 2 21
    5 6  4
    6 3 15
    7 2 14
    0 0  0
    
    输出样例#1:
    67

    说明

    NOIP 2000 提高组第四题

    思路:

      因为是两条路同时走,所以开了四维数组,i、j表示第一条路到达的点,l、k表示第二条路到达的点,走法又分为四种情况:

      ①两条路都从上边到达此点

      ②两条路都从左边到达此点

      ③第一条路从左边到达此点,第二条路由上边到达此点

      ④第一条路从上边到达此点,第二条路由左边到达此点

      因为是要最大和,所以每种情况都取max,最后所得的也是最大。如果两条路同时经过了一个点,那么这个点就只加一次,(我是按都加上,然后如果同时经过再减去一个写的)。

    (⊙v⊙)嗯,代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 
     5 const int N = 10;
     6 int n,x,y,sum[N][N],ans;
     7 int num[N][N],f[N][N][N][N],vis[N][N];
     8 
     9 int main() {
    10     scanf("%d",&n);
    11     while(scanf("%d%d",&x,&y)==2) {
    12         if(!x) break;
    13         cin>>sum[x][y];
    14     }
    15     for(int i=1; i<=n; i++) {
    16         for(int j=1; j<=n; j++) {
    17             for(int l=1; l<=n; l++) {
    18                 for(int k=1; k<=n; k++) {
    19                     if(i+j!=l+k) continue;
    20                     f[i][j][l][k] = max(f[i][j][l][k],f[i-1][j][l-1][k]);
    21                     f[i][j][l][k] = max(f[i][j][l][k],f[i][j-1][l][k-1]);
    22                     f[i][j][l][k] = max(f[i][j][l][k],f[i-1][j][l][k-1]);
    23                     f[i][j][l][k] = max(f[i][j][l][k],f[i][j-1][l-1][k]);
    24                     f[i][j][l][k]+=sum[i][j]+sum[l][k];
    25                     if(i==l&&j==k) f[i][j][l][k]-=sum[l][k];
    26                 }
    27             }
    28         }
    29     }
    30     cout<<f[n][n][n][n]<<endl;
    31     return 0;
    32 }

    自己选的路,跪着也要走完!!!

  • 相关阅读:
    如何让pc端网站在手机上可以等比缩放的整个显示
    CSS
    常见的IE布局兼容问题
    CSS : 使用 z-index 的前提
    CSS : object-fit 和 object-position实现 图片或视频自适应
    CSS
    vscode
    如何识别Form字段中一对多或者多对多字段
    window.open简单使用
    由一个模型拿它的名字、app的名字、字段对象以及字段对象中的属性
  • 原文地址:https://www.cnblogs.com/wsdestdq/p/6829870.html
Copyright © 2020-2023  润新知