P2370 yyy2015c01 的 U 盘

P2370 yyy2015c01 的 U 盘

基础思路

看到题目要求最小需要的最大接口。自然认为既然答案要求接口,那状态方程的值就是接口。

一开始状态方程F[i][j]\(i\)为前\(i\)个接口,\(j\)为当前体积。而F[i][j]则为当前最小的最大接口值

状态转移方程F[i][j] = min(F[i][j], (F[i - 1][j - v[i]] == INF) ? v[i] : max(F[i - 1][j - w[i]], v[i]))

然而这根本没法达到最优价值,更别提达到价值要求。

然后我又更改方程,\(j\)表示当前价值。但是这更错,首先当前价值未必最优,而且这下体积也没法保证小于U盘总体积。

冥思苦想,似乎要创造新背包算法了。

改进思路

然而,我的逻辑上有一个问题,我认为DP题一定要把答案设置为状态转移方程的值

实则未必,这道题剔除最大接口后,就是一个01背包的板子。

当跑完01背包后,如何判断最大接口是问题。

这里我觉得两种做法很好。

结合排序

直接先按照体积排序,这样找到答案(能装下的最大价值比要求价值大的状态)直接输出就是装入物品的最大体积,即要求的接口。

这个方法代码复杂度不高,很容易实现。但是思考复杂度还是有,比较难想到。

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

#define INF 0x7fffffff

using namespace std;

struct yyy
{
	int v, w;
	bool operator< (const yyy &rhs)
	const
	{
		return v < rhs.v;
	}
};

int n, p, s;
yyy a[1010];
int F[1010];

int main()
{
	cin >> n >> p >> s;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i].v >> a[i].w;
	}
	sort(a + 1, a + n + 1);
	for (int i = 1; i <= n; i++)
	{
		for (int j = s; j >= a[i].v; j--)
		{
			F[j] = max(F[j], F[j - a[i].v] + a[i].w);
			if (F[j] >= p)
			{
				printf("%d", a[i].v);
				return 0;
			}
		}
	}
	printf("No Solution!");
	return 0;
}

二分答案

首先看到最小的最大接口,很容易想出来可以二分答案。

思路也很明了,二分接口值,DP即可。

代码和思维都比较容易实现,就是时间复杂度可能略高。

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

#define INF 0x7fffffff

using namespace std;

struct yyy
{
	int v, w;
	bool operator< (const yyy &rhs)
	const
	{
		return v < rhs.v;
	}
};

int n, p, s;
yyy a[1010];
int F[1010];

bool DP(int x)
{
	memset(F, 0, sizeof(F));
	for (int i = 1; i <= n; i++)
	{
		if (a[i].v > x)
			continue;
		for (int j = s; j >= a[i].v; j--)
		{
			F[j] = max(F[j], F[j - a[i].v] + a[i].w);
			if (F[j] >= p)
			{
				return true;
			}
		}
	}
	return false;
}

int main()
{
	cin >> n >> p >> s;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i].v >> a[i].w;
	}
	int l = 1, r = s, ans = 0;
	while (l <= r)
	{
		int mid = l + ((r - l) >> 1);
		if (DP(mid))
		{
			ans = mid;
			r = mid - 1;
		}
		else
		{
			l = mid + 1;
		}
	}
	if (!ans)
		printf("No Solution!");
	else
		printf("%d", ans);
	return 0;
}

总结

这题主要是战略出现了问题,以后看dp问题的时候不能只有dp,应该想想结合其他算法。状态方程也未必要和答案直接挂钩。

posted @ 2023-11-04 17:30  加固文明幻景  阅读(9)  评论(0编辑  收藏  举报