c++ dp 贪婪的戈尔曼题解

1、题目:

从前有2只狗,大的叫大狗,小的叫小狗,它们2个合起来就是狗儿们,使用英语的人把它们写作Girlman,传来传去,到最后大家决定叫它们格尔曼。它们 的叫声很特别,但是它们十分吝啬它们的叫声,你为了听到它们的叫声,决定买狗饼干送给它们吃,不同种类的饼干能让它们叫的次数不一样,同一块饼干对于大小 格尔曼的效果也不一样。它们很贪婪,如果你只给其中一只格尔曼吃狗饼干或者给两只格尔曼吃的不一样,有一只就会不高兴,因此你买狗饼干的时候总要两块两块 地买,而且现在每类饼干也只有2块(想要多的也没得)。现在不是流行节约型社会吗?因此你也不能浪费,你要求的是在满足你要听格尔曼叫声次数要求的情况 (两只格尔曼实际叫的次数都不小于你的要求即可)下的最小花费是多少。

2、思路:

非常明确的01背包问题可以将限制条件从大到小遍历 ,但此题难点在于(个人观点)如何选出最小值而不是传统问题的最大值。

3正确代码:

#include <iostream>
#include<bits/stdc++.h>
#include <algorithm>
using namespace std;
long long int a[1005][3],dp[55][55]={0},max1=0;//dp的两个参量分别是小狗叫次数和大狗叫次数 
int main(){
	int n,xj,dj,ck1,ck2;//此处设立了两个参量(ck1,ck2)用于状态转移时参数的选用 
	cin>>n>>xj>>dj;
	memset(dp,0x3f3f3f,sizeof(dp));//初始化为无穷大 
	dp[0][0]=0;//显有两只狗叫的次数都为零时 花费为零 
	for(int i=1;i<=n;i++){
		cin>>a[i][0]>>a[i][1]>>a[i][2];
		a[i][2]=a[i][2]*2;
	}
	for(int i=1;i<=n;i++){
		for(int j=xj;j>=0;j--){	
			for(int w=dj;w>=0;w--){
				ck1=j+a[i][0];
				ck2=w+a[i][1];
				if(ck1>xj){
					ck1=xj;//超过所需值则按所需值处理 下同(因为两个参量都要达标所以有可能有参量超过所需值此处也是与传统01背包的不同之处) 
				}
				if(ck2>dj){
					ck2=dj;
				}
				dp[ck1][ck2]=min(dp[ck1][ck2],dp[j][w]+a[i][2]);//状态转移 
			}
		}
	}
	cout<<dp[xj][dj]<<endl;
    return 0;
}

 样例数据:

输入:

5 5 10
1 2 5
2 4 10
3 7 8
1 11 36
6 0 18

 输出:

36

错误代码(按照传统01背包问题写的):

#include <iostream>
#include<bits/stdc++.h>
#include <algorithm>
using namespace std;
int main(){
    int n,xj,dj;
    long long int a[1005][3],dp[55][55],max1=0;
    cin>>n>>xj>>dj;
    for(int i=1;i<=n;i++){
        cin>>a[i][0]>>a[i][1]>>a[i][2];
        a[i][2]=a[i][2]*2;
        if(max1<a[i][2]) max1=a[i][2];
    }
    for(int i=0;i<=xj;i++){
        for(int j=0;j<=dj;j++){
            dp[i][j]=max1;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=xj;j>=a[i][0];j--){    
            for(int w=dj;w>=a[i][1];w--){
                dp[j][w]=min(dp[j][w],dp[j-a[i][0]][w-a[i][1]]+a[i][2]);
                dp[j][w]=min(dp[j][w],dp[j][w-a[i][1]]+a[i][2]);
                dp[j][w]=min(dp[j][w],dp[j-a[i][0]][w]+a[i][2]);
            }
        }
    }
    cout<<dp[xj][dj];
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值