LCS与背包问题

LCS与背包问题

问题

动态规划中关于最长公共子序列 LCS 、完全背包的问题

解析

Xi = < x1,x2,…,xi >
Yj = < y1,y2,…,yj >
Zk = < z1,z2,…,zk >
如果Zk是Xi和Yj的最长公共子序列
(1)xi = yj,那么 zk = xi = yj,Zk-1 是 Xi-1 和Yj-1的最长公共子序列
(2)xi ≠ yj,zk ≠ xi,那么 Zk是Xi-1和 Yj 的最长公共子序列
(3)xi ≠ yj,zk ≠ yj,那么 Zk 是 Xi 和 Yj-1 的最长公共子序列

进而得出递推关系

实例:
X=<A,B,D,C,B,A,C>
Y=<B,C,A,D,A,A>
m=0-7
n=0-6

初始化

i/j 0 1 2 3 4 5 6
0 0 0 0 0 0 0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
算法1:
(1)i=1

j=1,X.A<>Y.B:C[1,1]=max(C[0,1],C[1,0])=max(0,0)=0,删除x
j=2,X.A<>Y.C:C[1,2]=max(C[0,2],C[1,1])=max(0,0)=0,删除x
j=3,X.AY.A:C[1,3]=C[0,2]+1=0+1=1,删除两个
j=4,X.A<>Y.D:C[1,4]=max(C[0,4],C[1,3])=max(0,1)=1,删除y
j=5,X.A
Y.A:C[1,5]=C[0,4]+1=0+1=1,删除两个
j=6,X.A==Y.A:C[1,6]=C[0,5]+1=0+1=1,删除两个
(2)i=2

j=1,X.B= =Y.B:X2==Y1,C[2,1]=C[1,0]+1=0+1=1,删除两个
j=2,X.B<>Y.C:X2<>Y2,C[2,2]=max(C[1,2],C[2,1])=max(0,1)=1,删除y
j=3,X.B<>Y.A:X2<>Y3,C[2,3]=max(C[1,3],C[2,2])=max(1,1)=1,删除x
j=4,X.B<>Y.D:X2<>Y4,C[2,4]=max(C[1,4],C[2,3])=max(1,1)=1,删除x
j=5,X.B<>Y.A:X2<>Y5,C[2,5]=max(C[1,5],C[2,4])=max(1,1)=1,删除x
j=6,X.B<>Y.A:X2<>Y6,C[2,6]=max(C[1,6],C[2,5])=max(1,1)=1,删除x
(3)i=3

j=1,X.D<>Y.B:X3<>Y1,C[3,1]=max(C[2,1],C[3,0])=max(1,0)=1,删除x
j=2,X.D<>Y.C:X3<>Y2,C[3,2]=max(C[2,2],C[3,1])=max(1,1)=1,删除x
j=3,X.D<>Y.A:X3<>Y3,C[3,3]=max(C[2.3],C[3,2])=max(1,1)=1,删除x
j=4,X.D= =Y.D:X3==Y4,C[3,4]=C[2,3]+1=2,删除两个
j=5,X.D<>Y.A:X3<>Y5,C[3,5]=max(C[2,5],C[3,4])=max(1,2)=2,删除y
j=6,X.D<>Y.A:X3<>Y6,C[3,6]=max(C[2,6],C[3,5])=max(1,2)=2,删除y
(4)i=4

j=1,X.C<>Y.B:X4<>Y1,C[4,1]=max(C[3,1],C[4,0])=max(1,0)=1,删除x
j=2,X.C= =Y.C:X4==Y2,C[4,2]=C[3,1]+1=2,删除两个
j=3,X.C<>Y.A:X4<>Y3,C[4,3]=max(C[3,3],C[4,2])=max(1,2)=2,删除y
j=4,X.C<>Y.D:X4<>Y4,C[4,4]=max(C[3,4],C[4,3])=max(2,2)=2,删除x
j=5,X.C<>Y.A:X4<>Y5,C[4,5]=max(C[3,5],C[4,4])=max(2,2)=2,删除x
j=6,X.C<>Y.A:X4<>Y6,C[4,6]=max(C[3,6],C[4,5])=max(2,2)=2,删除x
(5)i=5

j=1,X.B= =Y.B:X5==Y1,C[5,1]=C[4,0]+1=0+1=1,删除两个
j=2,X.B<>Y.C:X5<>Y2,C[5,2]=max(C[4,2],C[5,1])=max(2,1)=2,删除x
j=3,X.B<>Y.A:X5<>Y3,C[5,3]=max(C[4,3],C[5,2])=max(2,2)=2,删除x
j=4,X.B<>Y.D:X5<>Y4,C[5,4]=max(C[4,4],C[5,3])=max(2,2)=2,删除x
j=5,X.B<>Y.A:X5<>Y5,C[5,5]=max(C[4,5],C[5,4])=max(2,2)=2,删除x
j=6,X.B<>Y.B:X5<>Y6,C[5,6]=max(C[4,6],C[5,5])=max(2,2)=2,删除x
(6)i=6

j=1,X.A<>Y.B:X6<>Y1,C[6,1]=max(C[5,1],C[6,0])=max(1,0)=1,删除x
j=2,X.A<>Y.C:X6<>Y2,C[6,2]=max(C[5,2],C[6,1])=max(2,1)=2,删除x
j=3,X.AY.A:X6=Y3,C[6,3]=C[5,2]+1=2+1=3,删除两个
j=4,X.A<>Y.D:X6<>Y4,C[6,4]=max(C[5,4],C[6,3])=max(2,3)=3,删除y
j=5,X.A= =Y.A:X6
Y5,C[6,5]=C[5,4]+1=2+1=3,删除两个
j=6,X.A= =Y.A:X6==Y6,C[6,6]=C[5,5]+1=2+1=3,删除两个
(7)i=7

j=1,X.C<>Y.B:X7<>Y1,C[7,1]=max(C[6,1],C[7,0])=max(1,0)=1,删除x
j=2,X.C==Y.C:X7<>Y2,C[7,2]=C[6,1]+1=1+1=2,删除两个
j=3,X.C<>Y.A:X7<>Y3,C[7,3]=max(C[6,3],C[7,2])=max(3,2)=3,删除x
j=4,X.C<>Y.D:X7<>Y4,C[7,4]=max(C[6,4],C[7,3])=max(3,3)=3,删除x
j=5,X.C<>Y.A:X7<>Y5,C[7,5]=max(C[6,5],C[7,4])=max(3,3)=3,删除x
j=6,X.C<>Y.A:X7<>Y6,C[7,6]=max(C[6,6],C[7,5])=max(3,3)=3,删除x
B[i][j]

i/j 0 1 2 3 4 5 6
0 0 0 0 0 0 0 0
1 0 0;删除x 0;删除x 1;删除两个 1;删除y 1;删除两个 1;删除两个
2 0 1;删除两个 1;删除y 1;删除x 1;删除x 1;删除x 1;删除x
3 0 1;删除x 1;删除x 1;删除x 2;删除两个 2;删除y 2;删除y
4 0 1;删除x 2;删除两个 1;删除y 1;删除x 1;删除x 1;删除x
5 0 1;删除两个 2;删除x 2;删除x 2;删除x 2;删除x 2;删除x
6 0 1;删除x 2;删除x 3;删除两个 3;删除y 1;删除两个 3;删除两个
7 0 1;删除x 2;删除两个 3;删除x 3;删除x 3;删除x 3;删除x

int LCS() {
	C[0,j] = C[i,0] = 0,1≤i≤m,i≤j≤n
	for (i=1 to m) {
		for (j=1 to n) {
			if (X[i] == Y[j]) {
				C[i][j] = C[i - 1][j - 1] + 1;
				B[i][j] = 'D';
			}
			else if (C[i - 1][j] > C[i][j - 1]) {
				C[i][j] = C[i - 1][j];
				B[i][j] = 'X';
			}
			else {
				C[i][j] = C[i][j - 1];
				B[i][j] = 'Y';
			}
		}
	}
	return C[n - 1][m - 1];
}

完全背包问题

这里要区分背包问题,01背包是每种物品只能取0次或1次,而完全背包问题是每个物品取无限次

我们假设当前最优状态值为 d p [ i ] [ j ] dp[i][j]dp[i][j],即可选择前 i ii 个物品,背包大小为 j jj 时的最优状态值

考虑当前最佳状态为 d p [ i ] [ j ] dp[i][j]dp[i][j],那么 d p [ i ] [ j ] dp[i][j]dp[i][j] 可以由两个状态转移而来
是不选择第 i ii 个物品装入背包,那么 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j] = dp[i-1][j]dp[i][j]=dp[i−1][j]
选择第 i ii 个物品装入背包,那么 d p [ i ] [ j ] = d p [ i − 1 ] [ j − k ∗ w e i g h t [ i ] ] + k ∗ v a l [ i ] dp[i][j]=dp[i-1][j-kweight[i]] + kval[i]dp[i][j]=dp[i−1][j−k∗weight[i]]+k∗val[i]
这样的话我们就需要三重循环枚举物品的数量和物品的种类和背包的大小
所以我们可以通过滚动数组进行优化,减少循环次数和 d p dpdp 维度
根据公式推导

假设有 n = 5 n=5n=5 个物品, m = 10 m = 10m=10 的背包大小,物品的价值为 < 1 , 2 , 3 , 4 , 5 > <1,2,3,4,5><1,2,3,4,5>,重量为 < 5 , 4 , 3 , 2 , 1 > <5,4,3,2,1><5,4,3,2,1>

i/j 1 2 3 4 5 6 7 8 9 10
1 0 0 0 0 1 1 1 1 1 2
2 0 0 0 2 2 2 2 4 4 4
3 0 0 3 3 3 6 6 6 9 9
4 0 4 4 8 8 12 12 16 16 20
5 5 10 15 20 25 30 35 40 45 50

#include <iostream>
#define V 500
using namespace std;
int weight[20 + 1];
int value[20 + 1];
int f[V + 1];
int max(int a, int b) {
    return a > b ? a : b;
}
int main() {
    int n, m;
    cout << "请输入物品个数:";
    cin >> n;
    cout << "请分别输入" << n << "个物品的重量和价值:" << endl; 
    for (int i = 1; i <= n; i++) {
        cin >> weight[i] >> value[i];
    }
    cout << "请输入背包容量:";
    cin >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = weight[i]; j <= m; j++) {
            f[j] = max(f[j], f[j - weight[i]] + value[i]);
        }
    }
    cout << "背包能放的最大价值为:" << f[m] << endl;
}

源码

https://github.com/Ace16602/LCS-and-Bag

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值