算法分析设计 | 4.动态规划

真的就是一串C++11只有我一个傻der在用python35……
不过行少香啊……

DP策略 空间换时间
核心:记忆性,填表完成即找到最优解。
1.确定子问题
2.确定原问题和子问题间的递归式
3.确定存储子问题的数据结构
4.确定执行顺序
0-1背包

1 装箱问题

和“0-1背包”类似,就先写了,只不过是把背包中的二维数组表换成只计算“容量”的一维数组表。
python输入输出咱还在学
决策表使用两层循环,内层倒序(注意range步长用法),j 代表容量。这个解法的关键在于:逆向遍历 j,循环可以跳出,以优化 O ( n 2 ) O(n^2) O(n2)的时间复杂度。

v = int(input())
n = int(input())
box = [0] * n
dp = [0] * 40000
for i in range(n):
    box[i] = int(input())
for i in range(n):
    for j in range(v, 0, -1):
        if box[i] > j:
            break
        dp[j] = max(dp[j], dp[j-box[i]]+box[i])
print(v - dp[v])

那就把0-1背包的解法也给出(正着算):

v = int(input())
n = int(input())
vol = [0] * n
for i in range(n):
    vol[i] = int(input())
pri = [0] * n
for i in range(n):
    pri[i] = int(input())
dp = [[0] * 2000] * 2000
for i in range(n):
    for j in range(v):
        if j < vol[i]:
            dp[i][j] = dp[i-1][j]
        else:
            dp[i][j] = max(dp[i-1][j], dp[i-1][j-vol[i]]+pri[i])
        print(j, dp[i][j])
print(dp[n - 1][v - 1])

(反着来):

v = int(input())
n = int(input())
vol = [0] * n
for i in range(n):
    vol[i] = int(input())
pri = [0] * n
for i in range(n):
    pri[i] = int(input())
dp = [[0] * 2000] * 2000
for i in range(n):
    for j in range(v, -1, -1):
        if j < vol[i]:
            break
        dp[i][j] = max(dp[i-1][j], dp[i-1][j-vol[i]]+pri[i])
print(dp[n - 1][v])

2 过河

这个我就很是难受……头发都揪没了……
python + O ( n 2 ) O(n^2) O(n2)竟然内存超了。这个题使用正向,优化的方式是离散化
这是一种离散化的方法:石头间距大于s~t连乘时,中间的步骤是可省的,所以只需取余就可以。

stamp = 1
for i in range(s, t+1):
    stamp *= i
l = int(input()) 
s, t, m = map(int, input().split())  %使用map分别输入
sto = [int(i) for i in input().split()] % 输入一行的数组

d = [0] * m
for i in range(1, m):
    d[i] = (sto[i] - sto[i-1]) % 2250	% 计算新的间距
for i in range(1, m):
    sto[i] = sto[i-1] + d[i]	% 更新石头位置
del d[:]	% 尽力释放内存了

l = sto[m - 1] + t
dp = [m+1] * l
dp[0] = 0
for i in range(l):
    for j in range(s, t+1):
        if i-j < 0: break
        elif dp[i - j] != m+1:
            if i in sto:
                dp[i] = min(dp[i], dp[i-j]+1)
            else:
                dp[i] = min(dp[i], dp[i-j])
    print(dp[i-j:i])	% 测试
print(dp[l-1])

服了,我能看懂,但看不出差别
在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

int n, m, s, t, ans = 999999999;
int a[210];
int f[1000005];
int b[1000005];
int d[210];

int main()
{
	scanf("%d", &n);
	scanf("%d %d %d", &s, &t, &m);
	for (int i = 1; i <= m; i++) scanf("%d", &a[i]);
	sort(a + 1, a + 1 + m);
	for (int i = 1; i <= m; i++) d[i] = (a[i] - a[i - 1]) % 2520;
	for (int i = 1; i <= m; i++)
	{
		a[i] = a[i - 1] + d[i];
		b[a[i]] = 1;
	}
	n = a[m];
	memset(f, 127, sizeof(f));
	f[s] = 0;
	for (int i = 1; i <= n + t; i++)
	{
		for (int j = s; j <= t; j++)
		{
			if (i - j >= 0) f[i] = min(f[i], f[i - j] + b[i]);
		}
	}
	for (int i = n; i < n + t; i++) ans = min(ans, f[i]);
	printf("%d", ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值