动态规划笔试算法小结 C语言

给出了几种创建的动态规划题目适合笔试的解法,包含状态转移方程、状态转移矩阵(例子)和核心代码。子序列问题是需要复制元素在矩阵上侧或者左侧的值,而子串问题则不需要

目录

         1 强盗抢劫问题

2 最大公共子序列

3 最大公共子串

4 最大上升子序列

5 三角形最大路径长度

6 背包问题


1 强盗抢劫问题

问题:给定一个数组,表示一条街上每个房间的金钱数。盗贼抢劫这条街时,如果抢劫了相邻的两个房间,则会触发报警。问盗贼最多能抢到多少钱?

思路:就是看抢当前这个还是后一个哪个好

核心代码:

int rob(int Array[], int low, int high){
    int pre2=0, pre1=0;
    for(int i=low; i<=high; i++){
        int cur = max(pre2+Array[i], pre1);
        pre2 = pre1;
        pre1 = cur;
    }

    return pre1;
}

问题升级:第一个房子和最后一个房子成了邻居,所以我们就不可以同时把他们两家一块儿抢了

思路:1、如果打劫第一个房间,那么最后一个房间不可以打劫,只计算到n-1;

           2、如果不打劫第一个房间,那么可以考虑最后一个房间,从第2个房间开始计算,到第n个房间。然后再取两者的最大值

int max = max(rob(Array, 0, n-2), rob(Array, 1, n-1));

 

2 最大公共子序列

输入:"1A2C3D4B56","B1D23CA45B6A"

输出:6 (因为最大子序列是“123456”)

状态转移方程:

if(DP[i][j] == DP[i-1][j-1]):   DP[i][j] = DP[i-1][j-1]+1

else:   DP[i][j] = Max(DP[i-1][j], DP[i-1][j])

状态转移矩阵:

Max Common SubSequence
 B1D23CA45B6A 
10000000000000
A0011111111111
20011111222222
C0011222222222
30011223333333
D0011233333333
40012233333333
B0012233344444
50112233344555
60112233345555
 0112233345566

代码:

int main() {
    char str1[100],str2[100];
    printf("Input the String 1:");
    gets(str1);
    printf("Input the String 2:");
    gets(str2);

    int len1 = strlen(str1);
    int len2 = strlen(str2);
    int dp[len1+1][len2+1];
    memset(dp, 0, sizeof(dp));

    for(int i=1; i<len1+1; i++) {
        for(int j=1; j<len2+1; j++) {
            if(str1[i-1] == str2[j-1])
                dp[i][j] = dp[i-1][j-1]+1;
            else
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
            printf("%d ", dp[i][j]);
        }
        printf("\n");
    }

    printf("\n\n%d", dp[len1][len2]);

    return 0;
}

 

3 最大公共子串

输入:"1AB2345CD","12345EF"

输出:"2345"

状态转移方程:

    if(DP[i][j] == DP[i-1][j-1]): DP[i][j] = DP[i-1][j-1]+1

状态转移矩阵:

Max Common SubString
 12345EF 
100000000
A01000000
B00000000
200000000
300100000
400020000
500003000
C00000400
D00000000
 00000000

代码:

    int len1 = strlen(str1);
    int len2 = strlen(str2);
    int dp[len1+1][len2+1];
    memset(dp, 0, sizeof(dp));

    int max=0, end=0;
    for(int i=1; i<len1+1; i++)
        for(int j=1; j<len2+1; j++)
            if(str1[i-1]==str2[j-1]) {
                dp[i][j] = dp[i-1][j-1]+1;
                if(max<dp[i][j]){
                    max = dp[i][j];
                    end = i;
                }
            }

    if(max==0)
        printf("-1");
    else {
        for(int i=end-max; i<end; i++)
            printf("%c", str1[i]);
    }

 

4 最大上升子序列

输入:2 1 5 3 6 4 8 9 7

输出:4

状态转移方程:    if( Arr[i]>Arr[j] && Longest[i]<Longest[j]+1 )  Longest[i] = Longest[j]+1

状态转移矩阵:

Max Increase SubSeqence
215364897
11       
112      
1122     
11223    
112233   
1122334  
11223345 
112233454

代码:

int getMax(int Array[], int n){
    int longest[n], max=0;
    longest[0] = 1;

    for(int i=1; i<n; i++) {
        longest[i] =1;
        for(int j=0; j<i; j++){
            if(Array[j] < Array[i] && longest[i] < longest[j]+1) {
                longest[i] = longest[j]+1;
                if(longest[i]>max)
                    max = longest[i];
            }
        }
        for(int k=0; k<n; k++)
            printf("%d ", longest[k]);
        printf("\n");
    }

    return max;
}

 

5 三角形最大路径长度

输入:

5∥三角形行数。下面是三角形
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

输出:30

状态转移方程:DP[i][j] = Max(DP[i+1][j], DP[i+1][j+1])

状态转移矩阵:

Max Trangle Route
7    =>30    
38   2321   
810  201310  
2744 7121010 
4526545265

代码:

for(int i = n-2; i >= 0; --i)
    for(int j=0; j <= i; j++)
        Array[i][j] += max(Array[i+1][j], Array[i+1][j+1]);

 

6 背包问题

问题:一个旅行者有一个最多能装m公斤的背包,现在有n中物品,每件的重量分别是W1、W2、……、Wn,每件物品的价值分别为C1、C2、……、Cn,需要将物品放入背包中,要怎么样放才能保证背包中物品的总价值最大?

输入:

5 100    //n capacity
20 30
30 10
65 100
10 30
70 35

状态转移方程:

    if(weight[i]<j):  DP[i][j] = Max(DP[i-1][j], DP[i-1][j-weight[i]]+value[i])

    else:  DP[i][j] = DP[i-1][j]

状态转移矩阵:

Package Problem
5100   1...10...20...30...40...50...65...70...75...80...85...95...100
weightvalue  00000000000000000000000000
2030 200    303030303030303030303030303030303030303030
3010 300    303030303030404040404040404040404040404040
65100 650    3030303030304040100100100100100100100100130130130130130
1030 100  30303030303030304040100100100100130130130130130130160160160
7035 700  30303030303030304040100100100100130130130130130130160160160

代码:

#include<stdio.h>
#define  V 1500
int dp[10][V];//全局变量,自动初始化为0
int weight[10];
int value[10];
#define  max(x,y) (x)>(y)?(x):(y)
int main()
{

    //状态转移方程 dp[i+1][j]=max{dp[i][j],dp[i][j-weight[i+1]+value[i+1]}
    int n,capacity;
    scanf("%d %d",&n,&capacity);//N物品个数 M背包容量
    for (int i=1;i<=n; i++)
        scanf("%d %d",&weight[i],&value[i]);

    //动态规划
    for (int i=1; i<=n; i++)
        for (int j=1; j<=capacity; j++)
            if (weight[i]<=j)
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
            else
                dp[i][j]=dp[i-1][j]; //实际目的是为了防止地址越界
    printf("%d\n",dp[n][capacity]);//输出最优解
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值