P1510 精卫填海

P1510 精卫填海

最初思路

状态方程F[i]i是体积,F[i]指能填平该体积的最小体力。

推出转移方程F[i] = min(F[i], F[i-v[i]] + m[i])

但是代码实现只有10pts

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int v, n, c;
int k[10010], m[10010];
int F[100100];

int main() {
	cin >> v >> n >> c;
	for (int i = 1; i <= n; i++) {
		cin >> k[i] >> m[i];
	}
	for (int i = 1; i <= v + 5000; i++) {
		F[i] = 0x3f3f3f;
	}
	for (int i = 1; i <= n; i++) {
		for (int j = v; j >= k[i]; j--) {
			F[j] = min(F[j], F[j - k[i]] + m[i]);
		}
	}
	if (c - F[v] >= 0)
		cout << c - F[v];
	else
		cout << "Impossible";
	return 0;
}

思路改进

如果是按照\(01\)背包,这层for循环枚举到k[i]是没问题的

for (int j = v; j >= k[i]; j--) 
{
	F[j] = min(F[j], F[j - k[i]] + m[i]);
}

但是这是一个求最小值的问题,01背包不需要枚举\(j\)从零到\(k[i]\)的值是因为这些值本该为0,已经被提前初始化好了。

而求最小值的话,\(j\)从零到\(k[i]\)时要等于说要装填一个小于当前物品体积的东西,那只能取当前物品的体力值,毕竟没有比当前物品体积小的东西了,所以应加上\(j\)从零到\(k[i]\)的处理

for (int i = 1; i <= n; i++) 
{
		for (int j = v; j >= 0; j--) 
        {
			if (j >= k[i])
				F[j] = min(F[j], F[j - k[i]] + m[i]);
			else
				F[j] = min(F[j], m[i]);
		}
	}
posted @ 2023-11-03 10:58  加固文明幻景  阅读(3)  评论(0编辑  收藏  举报