金明的预算方案

 这题很好理解 五种方案大家都能想到 列举一下

(这里将主件和附件转化为父节点和他的左右儿子

 1. 什么都不选

 2.只选父节点

 3.父节点和左儿子

 4.父节点和右儿子

 5.父节点和两个儿子

 只要按这五种方案做01背包就可以了

但是今天的重点不是这个

重点是分享一下我的血泪史

先放一下输入

#include<bits/stdc++.h>
using namespace std;
int n,m;
int l[100],r[100];
int a[100];
int cash[100];
bool vis[100];
int p[100];
int dp[32010];
void init()
{
	memset(a,0,sizeof(a));
	memset(l,0,sizeof(l));
	memset(r,0,sizeof(r));
	memset(vis,0,sizeof(vis));
	memset(dp,0,sizeof(dp));
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int im;
		cin>>cash[i]>>im>>a[i];
		p[i]=cash[i]*im;
		if(a[i]!=0)
		{
			vis[i]=1;
			if(!l[a[i]]) l[a[i]]=i;
			else r[a[i]]=i;
		}
	}
}

第一次我的思路是 直接将最优值存入dp[i]

wa了四个点 并且我认为我的思路并没有错误 (有可能是因为没选主件直接选了附件 但是经过我的静态查错我认为我已经完全排除了这个可能

先上代码吧

void work()
{
	for(int i=1;i<=m;i++)
	{
		if(!vis[i]) //如果为父节点
		{
			 for(int j=n;j>0;j--) //是否取父节点
			 {
			 	int k=j-cash[i];
			 	if(k>=0) dp[j]=max(dp[j],dp[k]+p[i]);
			 }
			if(l[i]&&!r[i]) 是否取左儿子
			 for(int j=n;j>0;j--)
			 {
			 	int k=j-cash[i]-cash[l[i]];
			 	if(k>=0) dp[j]=max(dp[j],dp[k]+p[i]+p[l[i]]);
			 }
			if(l[i]&&r[i]) //取右儿子或者左右都取
			 for(int j=n;j>0;j--)
			 {
			 	int k1=j-cash[i]-cash[r[i]];
			 	int k2=k1-cash[l[i]];
			 	if(k1>=0) dp[j]=max(dp[j],dp[k1]+p[i]+p[r[i]]);
			 	if(k2>=0) dp[j]=max(dp[j],dp[k2]+p[i]+p[l[i]]+p[r[i]]);
			 }
		}
	}
	cout<<dp[n]<<endl;
}

后来我就转变了方法 先把当前父节点与他的儿子们的最优值存到一个数组里 然后与dp[i]比较 取最大值

void work()
{
	for(int i=1;i<=m;i++)
		if(!vis[i])
		{
			 int tmp[32010];
			 memset(tmp,0,sizeof(tmp));
			 for(int j=n;j>=cash[i];j--)
			 {
			 	int k=j-cash[i];
			 	tmp[j]=dp[k]+p[i];
			 }
			if(l[i]>0) //左儿子
			 for(int j=n;j>=cash[i]+cash[l[i]];j--)
			 {
			 	int k=j-cash[l[i]];
			 	tmp[j]=max(tmp[j],tmp[k]+p[l[i]]);
			 }
			if(r[i]>0) //右儿子
			 for(int j=n;j>=cash[i]+cash[r[i]];j--)
			 {
			 	int k=j-cash[r[i]];
			 	tmp[j]=max(tmp[j],tmp[k]+p[r[i]]);
			 }
			for(int j=1;j<=n;j++)
			dp[j]=max(tmp[j],dp[j]);
		}
	int ans=0;
	for(int i=1;i<=n;i++)
	ans=max(ans,dp[i]);
	cout<<ans<<endl;
}

然后这种方法是ac的

虽然说出来感觉没啥 但我真的非常非常非常非常郁闷!!!

一个晚上都献给了金明

的方案!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值