动态规划 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 }

 

 

 

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

 

posted @ 2017-05-09 11:43  橘生淮南终洛枳  阅读(214)  评论(0编辑  收藏  举报