您的位置:首页 > 其它

金明的预算方案

2018-03-21 21:06 225 查看


 这题很好理解 五种方案大家都能想到 列举一下
(这里将主件和附件转化为父节点和他的左右儿子
 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
<<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的
虽然说出来感觉没啥 但我真的非常非常非常非常郁闷!!!
一个晚上都献给了金明
的方案!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: