POJ 2392

POJ 2392
背包问题的变形+贪心。
这里的完全背包,有个数限制,而且,还有每个的最大容量还不一样。
我们可以贪心一下,让最高从低到高排序,可以证明出来,先让最大高度低的砌墙,一定会是最优解。
然后我们可以思考状态转移方程。
令j=需要的费用
bool dp[j[=dp[j-h[i]];做滚动数组,j从c[i]到a[i];
表示可以加起来的状态有哪些,而且这里个数已经暗含在了dp方程里面,因为假如h=5;
那么j=10的时候,dp[5]是可以到达的,10-5=5,dp[10]=dp[5],那么5就是可以达到的,就变成了滚动的累加。
那么问题来了,这道题还要求了我们个数,同理,我们在嵌套一个关于当前个数的另一个dp方程,
来维护当前状态下的,已经用了的个数。
sum[j]=sum[j-h[i]]+1;
代码如下

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const long long INF = 0x3f3f3f3f;
using namespace std;
int k;
struct a1 {
	int h, a, c;
}tw[500];
bool cmp(a1 s, a1 b)
{
	return s.a < b.a;
}//贪心排序
int sum[40005];
int dp[40005];
int main()
{
	cin >> k;
	int maxn = 0;
	up(i, 0, k)
	{
	//cin >> tw[i].h >> tw[i].a >> tw[i].c;
		scanf("%d %d %d", &tw[i].h, &tw[i].a, &tw[i].c);
		maxn = max(maxn, tw[i].a);//找到最大可以到达的位置
	}
	sort(tw, tw + k, cmp);
	dp[0] = 1;//0一定是可以达到的状态
	up(i, 0, k)
	{
		memset(sum, 0, sizeof(sum));//每次初始化维护数组个数的sum
		upd(j, tw[i].h, tw[i].a)
		{
			if (dp[j - tw[i].h] && sum[j - tw[i].h] < tw[i].c&&!dp[j])
			//j已经有值了就不需要在累加了,让sum[j]=0;
			{
				//cout << "i" << i << " j " << j;
				dp[j] = dp[j - tw[i].h];//bool值转移
				sum[j] = sum[j - tw[i].h] + 1;//等于上一个加一
			}
		}
		//cout << endl;
	}
	dwd(i, maxn, 0)
	{
		if (dp[i])//从后往前,找到第一个bool=true可以达到的状态
		{
			cout << i;
			return 0;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44019404/article/details/88255999
POJ
今日推荐