hdu5616 (01背包或者折半枚举)

题意:n个砝码,给你若干个重物,问你是否能称出来。

题解:

n只有20所,直接枚举有三种状态,放左边,放右边,不放。共有3^20次方情况。

如果枚举一半,找另一半,找另一半共有2*(3^10)次方复杂度,方法可行。

还有一种折半方法,把20个物品重量取相反数变为40个物品,然后对于这40个物品的取放便包含了所有情况。直接枚举复杂度2^40,这题的重量很小,重复量很多,其实暴力枚举可以水过去。而另一种方法当然也是折半枚举,复杂度2*(2^20)。

最好理解的当然是01背包啦,这题物品重量不超过2000,超过2000肯定无解。我们直接对20个物品做个01背包,然后反过来对他们的相反数做个01背包就行了。注意加法背包和减法背包第二层循环方向是不同的。下面给出01背包代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

int dp[4005];
int a[30];
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		memset(dp,0,sizeof(dp));
		for(int i=0;i<n;i++)cin>>a[i];
		dp[0]=1;
		
		
		for(int i=0;i<n;i++)
		for(int j=2000;j>=a[i];j--)
		dp[j]|=dp[j-a[i]];
		
		for(int i=0;i<n;i++)
		for(int j=0;j<=2000;j++)
		dp[j]|=dp[j+a[i]];
		
		int m;cin>>m;
		while(m--)
		{
			int x;cin>>x;
			if(x>2000)printf("NO\n");
			else if(dp[x]) printf("YES\n");
			else printf("NO\n");
		}
	}
	return 0;
}



猜你喜欢

转载自blog.csdn.net/qq_37632935/article/details/79976002