金明的预算方案-DP

https://vjudge.net/problem/HRBUST-1377
本题由三种思路,但是第三种和第一种感觉差不多。
1 可以发现一个物品最多五种状态。于是用5种状态进行01背包。
要注意 状态转移的过程。
2 树形dp,其实也是01背包的层次过程。。
3 分组背包。但是同普通的分组背包不一样的是,选附件也要选主件。所以我在 分组数据里放一个(0,0)。dp的时候加上主件。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=70;
int a[maxn];
int b[maxn];
int belong[maxn];
int dp[maxn][32100];
int m,n;
int treedp(int cost,int num){
  if(cost>0){
    for(int i=1;i<=n;i++){
        if(belong[i]==num)//如果属于是当前节点的自孩子背包
        { for(int j=0;j<=cost-a[i];j++)
            dp[i][j]=dp[num][j]+a[i]*b[i];//装进去这个点。
            treedp(cost-a[i],i);
            for(int x=0;x<=cost;x++)
                if(x>=a[i])
                dp[num][x]=max(dp[num][x],dp[i][x-a[i]]);
                else
                    dp[num][x]=dp[num][x];

        }
    }
  }
  return 0;
}
int main()
{
     while(~scanf("%d%d",&m,&n)){
          //m/=100;
          memset(dp,0,sizeof(dp));
          for(int i=1;i<=n;i++){
             scanf("%d%d%d",&a[i],&b[i],&belong[i]);
          }
     
          treedp(m,0);
          for(int i=0;i<=n;i++){
            for(int j=0;j<=m;j++)
                printf("%d ",dp[i][j]);
            cout<<endl;

          }

         printf("%d\n",dp[0][m]);

     }


    return 0;
}

转化成01背包

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
/*第一种方法:直接分5种情况。
每种进行01 背包(意思就是啊,
这5种情况只会发生一种情况)
第二种:
*/
const int maxn = 40000;
int dp[70][maxn];
int value[70][3],imp[70][3];

int main()
{
	int n,m;
	int v,p,q;
	while(~scanf("%d%d",&m,&n)){
          memset(value,0,sizeof(value));
          memset(imp,0,sizeof(imp));
          memset(dp,0,sizeof(dp));
          for(int i=1;i<=n;i++){
             scanf("%d%d%d",&v,&p,&q);
             if(!q){
                value[i][0]=v;
                imp[i][0]=p;
             }
             else{
                    if(!value[q][1]){
                     value[q][1]=v;
                     imp[q][1]=p;
                     }
                     else{
                        value[q][2]=v;
                        imp[q][2]=p;
                     }
             }
          }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(j>=value[i][0]){
dp[i][j]=max(dp[i-1][j],dp[i-1][j-value[i][0]]+value[i][0]*imp[i][0]);
                if(j>=(value[i][0]+value[i][1]))
dp[i][j]=max(dp[i][j],dp[i-1][j-value[i][0]-value[i][1]]+value[i][0]*imp[i][0]+value[i][1]*imp[i][1]);
                if(j>=(value[i][0]+value[i][2]))
dp[i][j]=max(dp[i][j],dp[i-1][j-value[i][0]-value[i][2]]+value[i][0]*imp[i][0]+value[i][2]*imp[i][2]);
                if(j>=(value[i][0]+value[i][2]+value[i][1]))
dp[i][j]=max(dp[i][j],dp[i-1][j-value[i][0]-value[i][2]-value[i][1]]+value[i][0]*imp[i][0]+value[i][2]*imp[i][2]+value[i][1]*imp[i][1]);
                }
                else
                    dp[i][j]=dp[i-1][j];
            }
        }
  printf("%d\n",dp[n][m]);
    }
	return 0;
}
#include <iostream>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;
const int maxn=70;
vector<pair<int,int> >v[maxn];
int va[maxn];
int imp[maxn];
int dp[50006];
// 分组背包,比01背包泛化能力要强。
int main()
{   int m,allv,temp;
    scanf("%d%d",&allv,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&va[i],&imp[i],&temp);
        if(!temp){
           v[i].push_back(make_pair(0,0));
           ;
        }
        else{
            int siz=v[temp].size();
            for(int j=0;j<siz;j++)
                v[temp].push_back(make_pair(va[i]+v[temp][j].first,imp[i]*va[i]+v[temp][j].second));
             //v[temp].push_back(make_pair(va[i],va[i]*imp[i]));
        }
    }

    memset(dp,0,sizeof(dp));
    for(int i=1;i<=m;i++){
        if(!v[i].size())continue;
        //for(int j=0;j<v[i].size();j++){
            //cout<<v[i][j].first<<"wupin"<<v[i][j].second<<endl;

            for(int val=allv;val>=0;val--){
                for(int j=0;j<v[i].size();j++)
                    if(val>=v[i][j].first+va[i])
                 dp[val]=max(dp[val-v[i][j].first-va[i]]+v[i][j].second+va[i]*imp[i],dp[val]);
            }
        //}
    }
    printf("%d\n",dp[allv]);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值