赞
踩
1、根绝问题所求的那一项和变量的个数,确定是一维数组,二维数组或者多维数组。
2、写出初始值,一般是某个变量为1或者0 的特殊情况时候的解。
3、通过循环,一般是两个循环中间每一层循环表示一个变量的递增情况。
4、在循环中间写出对应的递推关系表达式,求出问题的每一项。
5、根据题意得到答案,一般是数组的最后一项。
提示 : 找递推关系是动态规划最难的一步,所以不要懒,一定要在草稿纸上去画出来二维表的情况,一般只要看看自己画的表就可以得到规律。
有一个矩阵map,它每个格子有一个权值。从左上角的格子开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,返回所有的路径中最小的路径和。给定一个矩阵map及它的行数n和列数m,请返回最小路径和。保证行列数均小于等于100.
输入输出样例:
第一行,输入n,m表示这个矩阵的行数和列数,接下来的n行,输入每行的m个数字,也即每个格子的权值。最后输出最小路径和。如:
2 3
1 2 3
1 1 1
输出:4
因为只能向右和向下,所以从第一个格子到某个格子(不在第一排也不在第一列,否则没有编程的必要了)的最短距离只与第一个格子到它左边格子的最短距离以及第一个格子到它上面格子的最短距离这两个值有关,取这两个值中的较小者。可以设dp[n][m]为走到n*m位置的最短路径长度,则dp[n][m] = Min(dp[n-1][m],dp[n][m-1]),这就运用到了动态规划的思想。题目要求算出复杂情况的值,而动态规划则是算出几个简单的作为已知值,然后找规律由后往前推理。
3.代码如下:
- #include<stdio.h>
- #include<stdlib.h>
- int a[100][100];
- int dp[100][100];
-
- int Min(int a,int b){
- if(a<b){
- return a;
- }else{
- return b;
- }
- }
-
- int getMin(int m,int n){
- int min;
-
- dp[0][0]=a[0][0];
- for(int i=1;i<m;i++){
- dp[i][0]=a[i][0]+dp[i-1][0];
- }
- for(int i=1;i<n;i++){
- dp[0][i]=a[0][i]+dp[0][i-1];
- }
-
- for(int i=1;i<m;i++){
- for(int j=1;j<n;j++){
- min=Min(dp[i-1][j],dp[i][j-1]);
- dp[i][j]=min+a[i][j];
- }
- }
-
- return dp[m-1][n-1];
- }
-
- int main(){
- int m,n;
- scanf("%d%d",&m,&n);
-
- for(int i=0;i<m;i++){
- for(int j=0;j<n;j++){
- scanf("%d",&a[i][j]);
- }
- }
-
- printf("%d\n",getMin(m,n));
-
- return 0;
- }
给定两个字符串A和B,返回两个字符串的最长公共子序列的长度。例如,A="1A2C3D4B56”,B="B1D23CA45B6A”,”123456"或者"12C4B6"都是最长公共子序列。给定两个字符串A和B,同时给定两个串的长度n和m,请返回最长公共子序列的长度。保证两串长度均小于等于300。测试样例:第一行输入一个字符串,第二行输入这个字符串的长度,第三行和第四行也分别输入一个字符串和这个字符串的长度。最后输出结果。如:1A2C3D4B56
10
B1D23CA45B6A
12返回:6
- #include<stdio.h>
- #include<string.h>
- int dp[100][100];
-
- int Max(int a,int b,int c){
- int max=a;
- if(b>max){
- max=b;
- }
- if(c>max){
- max=c;
- }
- return max;
- }
-
- int getMax(char s1[],char s2[],int m,int n){
- int i,j;
-
- for(i=0;i<m;i++){ //当 s2取 1个的时候 ,s1为可变长度
- if(s1[i]==s2[0]){
- dp[i][0]=1;
- for(j=i+1;j<m;j++){
- dp[j][0]=1;
- }
- break;
- }
- }
- for(i=0;i<n;i++){ //当 s1取 1个的时候 ,s2为可变长度
- if(s2[i]==s1[0]){
- dp[0][i]=1;
- for(j=i+1;j<n;j++){
- dp[0][j]=1;
- }
- break;
- }
- }
-
- for(i=1;i<m;i++){
- for(j=1;j<n;j++){
- if(s1[i]==s2[j]){
- dp[i][j]=Max(dp[i-1][j-1]+1,dp[i-1][j],dp[i][j-1]);
- }else{
- dp[i][j]=dp[i-1][j]>=dp[i][j-1]?dp[i-1][j]:dp[i][j-1];
- }
- }
- }
- return dp[m-1][n-1];
- }
-
- int main(){
- int m,n;
- char s1[100];
- char s2[100];
- gets(s1);
- gets(s2);
- m=strlen(s1);
- n=strlen(s2);
-
- printf("%d\n",getMax(s1,s2,m,n));
-
- return 0;
- }
三、密码脱落
1.问题引入:
X星球的考古学家发现了一批古代留下来的密码。
这些密码是由A、B、C、D 四种植物的种子串成的序列。
仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。
由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。
你的任务是:
给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子。
输入一行,表示现在看到的密码串(长度不大于1000)
要求输出一个正整数,表示至少脱落了多少个种子。
例如,输入:
ABCBA
则程序应该输出:
0
再例如,输入:
ABDCDCBABC
则程序应该输出:
3
- #include<stdio.h>
- #include<string.h>
- int dp[100][100];
-
- int Max(int a,int b,int c){
- int max=a;
- if(b>max){
- max=b;
- }
- if(c>max){
- max=c;
- }
- return max;
- }
-
- int getMax(char s1[],char s2[],int m){
- int i,j;
- for(i=0;i<m;i++){
- if(s1[0]==s2[i]){
- dp[0][i]=1;
- for(j=i+1;j<m;j++){
- dp[0][j]=1;
- }
- break;
- }
- }
- for(int i=0;i<m;i++){
- if(s1[i]==s2[0]){
- dp[i][0]=1;
- for(j=i+1;j<m;j++){
- dp[j][0]=1;
- }
- break;
- }
- }
-
- for(i=1;i<m;i++){
- for(j=1;j<m;j++){
- if(s1[i]==s2[j]){
- dp[i][j]=Max(dp[i-1][j-1]+1,dp[i-1][j],dp[i][j-1]);
- }else{
- dp[i][j]=dp[i-1][j]>=dp[i][j-1]?dp[i-1][j]:dp[i][j-1];
- }
- }
- }
-
- return m-dp[m-1][m-1];
- }
-
- int main(){
- int m,n;
- char s1[100];
- char s2[100];
- gets(s1);
- m=strlen(s1);
- for(n=0;n<m;n++){
- s2[n]=s1[m-n-1];
- }
-
- printf("%d\n",getMax(s1,s2,m));
-
- return 0;
- }
假设现在有面值为1元、3元和5元的硬币若干枚,如何用最少的硬币凑够需要的钱数。现输入一个数,表示需要的钱数,要求输出一个整数表示最小的硬币数。
- #include<stdio.h>
- int min[10000];
- int kinds[]={5,2,1};
-
- int f(int n,int m){
- min[0]=0;
- min[1]=1;
- for(int i=2;i<m+1;i++){
- int a=m;
- for(int j=0;j<n;j++){
- if(kinds[j]<=i){
- int t=min[i-kinds[j]]+1;
- a=a<t?a:t;
- }
- }
- min[i]=a;
- }
- return min[m];
- }
-
- int main(){
-
- int m;
- scanf("%d",&m);
- printf("%d\n",f(3,m));
- return 0;
- }
五、K好数
如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数。求L位K进制数中K好数的数目。例如K = 4,L = 2的时候,所有K好数为11、13、20、22、30、31、33 共7个。由于这个数目很大,请你输出它对1000000007取模后的值。
输入包含两个正整数,K和L。
对于30%的数据,KL <= 106;
对于50%的数据,K <= 16, L <= 10;
对于100%的数据,1 <= K,L <= 100。
2.思路:
第i位数放置j所得到的所有K好数由i-1进制数的所有K好数之和去除与j相邻的两种情况求得。
#include<stdio.h>
int dp[100][100];
int getAns(int k,int l){
int i,j,t,sum=0;
for(i=0;i<k;i++){
dp[1][i]=1;
}
for(i=2;i<=l;i++){
for(j=0;j<k;j++){
for(t=0;t<k;t++){
if(t!=j-1&&t!=j+1){
dp[i][j]+=dp[i-1][t];
}
}
}
dp[i][j]%=100000008;
}
for(j=1;j<k;j++){
sum=sum+dp[l][j];
sum%=100000008;
}
return sum;
}
int main(){
int k,l;
scanf("%d%d",&k,&l);
printf("%d\n",getAns(k,l));
return 0;
}
name | weight | value | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
a | 2 | 6 | 0 | 6 | 6 | 9 | 9 | 12 | 12 | 15 | 15 | 15 |
b | 2 | 3 | 0 | 3 | 3 | 6 | 6 | 9 | 9 | 9 | 10 | 11 |
c | 6 | 5 | 0 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 10 | 11 |
d | 5 | 4 | 0 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 10 | 10 |
e | 4 | 6 | 0 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
通过找规律手工填写出上面这张表就能理解背包的动态规划算法了。状态转移方程为:
f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ),//表示第i件物品放入
f[i-1,j] //表示第i件物品不放入}
- #include<stdio.h>
- int v[]={6,3,5,4,6};
- int w[]={2,2,6,5,4};
- int dp[100][100];
-
- int Max(int a,int b){
- if(a>=b){
- return a;
- }else{
- return b;
- }
- }
-
- int getAns(int i,int wi){
-
- for(int x=0;x<=i;x++){
- dp[x][0]=0;
- }
- for(int x=0;x<=wi;x++){
- dp[0][x]=0;
- }
-
- for(int x=1;x<=i;x++){
- for(int y=1;y<=wi;y++){
- if(y>=w[x-1]){
- dp[x][y]=Max(dp[x-1][y],v[x-1]+dp[x-1][y-w[x-1]]);
- }else{
- dp[x][y]=dp[x-1][y];
- }
- printf("%4d",dp[x][y]);
- }
- printf("\n");
- }
- return dp[i][wi];
- }
-
-
- int main(){
- int max=getAns(5,10);
- printf("%d\n",max);
- return 0;
- }
- #include<stdio.h>
- #define x 9999;
- #define max 9999;
- int dist[10];
-
- void f(int a[][11]){
- int i,j,k;
- dist[0]=0;
- for(i=1;i<10;i++){
- k=max;
- for(j=0;j<i;j++){
- if(a[j][i]!=0){
- if(dist[j]+a[j][i]<k){
- k=dist[j]+a[j][i];
- }
- dist[i]=k;
-
- }
- }
- }
- }
-
- int main(){
- int i;
- int a[][11] = { { 0, 4, 2, 3, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 10, 9, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 6, 7, 10, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 3, 8, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 4, 8, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 9, 6, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 5, 4, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 8 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 4 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
- f(a);
- printf("%d\n",dist[9]);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。