【题解】「P1504」积木城堡

这题是01背包((DP))

如何判断要拆走那个积木,首先定义一个(ans)数组,来存放这对积木能拼成多高的,然后如果(ans_i = n)那么就说明这个高度的积木可以。

话不多说,上代码!

#include<cstdio> //从最小高度~1枚举, 如果能恰好达到这个高度(即用它有的积木恰好能拼出)有n个城堡
#include<cstring>
#include<algorithm>
using namespace std;

int n, len, min_high = 2e9;
//n表示城堡数,len表示每块立方体积木的棱长, min_high表示所有城堡初始高度最小值 
int w[10005],ans[10005]; //设ans[i]表示i能被多少组w[1..n]凑成,当dp[i]==true时,ans[i]++
//w[i]表示组成这座城堡的第i块积木的棱长 
bool dp[10005]; //dp[i]表示能否使用当前的w[1..n]相加得到i
/* 有n件物品(积木),每件物品体积(积木的棱长)为w[i], 价值(积木的棱长)为w[i]。
有容量(城堡高度)为 V 的背包(城堡)。求在容量(城堡高度)允许的范围下,背包装入物品的价值和(积木的棱长和)有哪些可能值。*/ 


int main()
{
	scanf("%d", &n);
	for(int k = 1; k <= n; k++)
	{
		memset(dp, 0, sizeof(dp));
		int cnt = 1, high = 0; //cnt表示每座城堡含积木的块数,high表示每座城堡的初始高度 
		while(1)
		{
			scanf("%d", &w[cnt]); //len表示组成这座城堡的每块积木的棱长
			if(w[cnt] == -1) break;
			high += w[cnt];
			cnt++;
		}
		dp[0] = 1; // dp[0] = 1表示能使用当前的w[1..n]相加得到高度0
		min_high = min(min_high, high); //求出所有城堡初始高度最小值 
        for(int i = 1; i < cnt; i++) //对每座城堡从1~g去枚举每一块积木 
			for(int j = high; j >= w[i]; j--)
				dp[j] = dp[j] || dp[j-w[i]]; //01背包变形,即动态转移方程
		for(int i = high; i >= 1; i--)
        	if(dp[i] == true) ans[i]++; //统计高度i出现次数
	}
    for(int i = min_high; i >= 1; i--) //从最小高度~1枚举
		if(ans[i] == n) //如果能恰好达到这个高度(即用它有的积木恰好能拼出)有n个城堡
		{
			printf("%d
", i);  
			return 0;
		}
	printf("0
");
    
	return 0;
}

(Bye Bye!)

原文地址:https://www.cnblogs.com/-TNT-/p/solution-p1504.html