算法分析与设计作业9实现LCS算法和背包算法

1.问题

Lcs:
给定序列X=<x1,x2,…,xm>,Y=<y1,y2,…,yj>,求X和Y的最长公共子序列。
背包问题:
有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?

2.解析

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-1是Xi-1和Yj的最长公共子序列
(3)xi ≠ yj,那么zk ≠ yi,Zk-1是Xi和Yj-1的最长公共子序列
举例:
X=<A, B, C, B>
Y=<B, A, C>
m=0-4
n=0-3
1.i=1
a) j=1 X.A<>Y.B: C[1,1]=max(C[1,0], C[0,1])= max(0, 0)=0, 删除 y
b) j=2 X.A==Y.A: C[1,2]= C[0,1]+1 =1, 删除两个
c) j=3 X.A<>Y.C: C[1,3]=max(C[1,2], C[0,3])= max(1, 0)=1, 删除 y

2.i=2
a) j=1 X.B==Y.B: C[2,1] = C[1,0]+1 =1, 删除两个
b) j=2 X.B<>Y.A: C[2,2]= max(C[2,1], C[1,2])= max(1, 0)=1, 删除 y
c) j=3 X.B<>Y.C: C[2,3]=max(C[2,2], C[1,3])= max(1, 1)=1, 删除 y

3.i=3
a) j=1 X.C<>Y.B: C[3,1]=max(C[3,0], C[2,1])= max(0, 1)=1, 删除 x
b) j=2 X.C<>Y.A: C[3,2]= max(C[3,1], C[2,2])= max(1, 1)=1, 删除 y
c) j=3 X.C==Y.C: C[3,3]= C[2,2]+1 =2, 删除两个

4.i=4
a) j=1 X.D<>Y.B: C[4,1]=max(C[4,0], C[3,1])= max(0, 1)=1, 删除 x
b) j=2 X.D<>Y.A: C[4,2]=max(C[4,1], C[3,2])= max(1, 1)=1, 删除 y
c) j=3 X.D<>Y.C: C[4,3]=max(C[4,2], C[3,3])= max(1, 2)=2, 删除 x
根据上面四条数据建立表。
再依据三条规则,最后得到结果<B , C>
在这里插入图片描述
背包算法:
当前Fk-1(y1)最大价值:后续两种策略

  1. 继续装 k-1 号物品
  2. 装 k 号物品

Fk(y)表示只允许装前 k 种物品,背包总重不超过 y(重量)时背包的最大价值
1.不装第 k 种物品: Fk-1(y)
2.至少装 1 件 k 中物品:仅仅装一件物品 k,排除一件物品 k 后(减去重量,加上其价值)递归(可能再减一件物品 k,或者 k-1 物品),物品 k 的重量和价值分别为 wk,vk;Fk(y-wk)表示在(y-wk)重量中,(已排
除一件 k 物品的前提下)只允许装前 k 种物品时的最大价值。
3.F0(y)表示背包不装物品的价值
4.Fk(y)背包重量限制为 0 时的最大价值
5.F1(y)只装第一种物品,[y/w1]个数
6.Fk(y)=-∞用于比较
在这里插入图片描述
举例:
体积:2 3 4 5
重量:3 4 5 6

  1. 填表,首先初始化边界条件,V(0,j)=V(i,0)=0
  2. 如,i=1,j=1,w(1)=2,v(1)=3,有j<w(1),故V(1,1)=V(1-1,1)=0;又如i=1,j=2,w(1)=2,v(1)=3,有j=w(1),故V(1,2)=max{V(1-1,2),V(1-1,2-w(1))+v(1) }=max{0,0+3}=3;如此下去,填到最后一个,i=4,j=8,w(4)=5,v(4)=6,有j>w(4),故V(4,8)=max{V(4-1,8),V(4-1,8-w(4))+v(4) }=max{9,4+6}=10
  3. 最后的得出的结果Vmax=V(4,8)=10

3.设计

Lcs:

void z(int B[][130], int i, int j) {
	if (i == 0 || j == 0) {//长度为0跳出
		return;
	}
	if (B[i][j] == 2) {
		z(B, i - 1, j - 1);
		printf("%c ", X[i]);//输出符合的字母
	}
	else if (B[i][j] == 1) {
		z(B, i - 1, j);
	}
	else {
		z(B, i, j - 1);
	}
}
void LCS(char X[], int m, char Y[], int n, int C[][130], int B[][130]) {
	for (int i = 1; i <= m; i++)
	{
		for (int j = 1; j <= n; ++j) {
			if (X[i] == Y[j]) {//第一种情况,这时Zk-1是Xi-1和Yj-1的最长公共子序列
				C[i][j] = C[i - 1][j - 1] + 1;
				B[i][j] = 2;
			}
			else
			{
				if (C[i - 1][j] > C[i][j - 1])//第二种情况,这时Zk-1是Xi-1和Yj的最长公共子序列
				{
					C[i][j] = C[i - 1][j];
					B[i][j] = 1;
				}
				else {
					C[i][j] = C[i][j - 1];//第三种情况,这时Zk-1是Xi和Yj-1的最长公共子序列
					B[i][j] = 0;
				}
			}
		}
	}
	z(B, m, n);
}

背包问题:

void Knapsack(int v[], int w[], int c, int n, int m[][10])
{
	int jMax = min(w[n] - 1, c);//背包剩余容量上限 范围[0~w[n]-1]
	for (int j = 0; j <= jMax; j++)
	{
		m[n][j] = 0;
	}

	for (int j = w[n]; j <= c; j++)//限制范围[w[n]~c]
	{
		m[n][j] = v[n];
	}

	for (int i = n - 1; i > 1; i--)
	{
		jMax = min(w[i] - 1, c);
		for (int j = 0; j <= jMax; j++)//背包不同剩余容量j<=jMax<c
		{
			m[i][j] = m[i + 1][j];//没产生任何效益
		}

		for (int j = w[i]; j <= c; j++) //背包不同剩余容量j-wi >c
		{
			m[i][j] = max(m[i + 1][j], m[i + 1][j - w[i]] + v[i]);
		}
	}
	m[1][c] = m[2][c];
	if (c >= w[1])
	{
		m[1][c] = max(m[1][c], m[2][c - w[1]] + v[1]);
	}
}
//x[]数组存储对应物品0-1向量,0不装入背包,1表示装入背包
void Traceback(int m[][10], int w[], int c, int n, int x[])
{
	for (int i = 1; i < n; i++)
	{
		if (m[i][c] == m[i + 1][c])
		{
			x[i] = 0;
		}
		else
		{
			x[i] = 1;
			c -= w[i];
		}
	}
	x[n] = (m[n][c]) ? 1 : 0;
}

4.分析

Lcs的时间复杂度为O(mn).
背包问题的时间复杂度为O(n^2)

5.源码

Lcs
背包问题

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值