动态规划和贪心算法问题(应用篇)

1 0-1背包问题(腾讯2014年笔试)
“背包题目”的基本描述是:有一个背包,能盛放的物品总重量为S,设有N件物品,其重量分别为w1,w2,…,wn,希望从N件物品中选择若干物品,所选物品的重量之和恰能放进该背包,即所选物品的重量之和即是S。递归和非递归解法都能求得“背包题目”的一组解,试写出“背包题目”的非递归解法。

#include<iostream>
#include<string>
#include<algorithm>
#include<numeric>
#include<fstream>
using namespace std;
#define MAXLEN 20
#define MAXW   100

void Backage(int WN[],int n,int W){ //n件物品的重量已知,选取k个恰好放进容量为W的包里,k的选择方案
    bool dp[MAXLEN][MAXW];         //取k个数和为s是否存在
    memset(&(dp[0][0]),0,sizeof(dp));
    dp[0][0]=true;
    ofstream out("1.txt");
    for(int k=1;k<=n;k++){//取k个数
        for(int k0=k;k0>=1;k0--){
            for(int s=1;s<=W;s++){
                if(s>=WN[k-1]&&dp[k0-1][s-WN[k-1]])
                    dp[k0][s]=true;
                out<<k0<<","<<s<<"  "<<dp[k0][s]<<endl; 
            }
        }
    }
    int count=0;
    for(int i=1;i<=n;i++){
        if(dp[i][W]){
            count++;
            cout<<i<<endl;     
        }
    }
    cout<<count<<endl;  //标记选取物品的件数
}
int main(){
    int WN[]={1,2,3,4,5,6,7};
    int W=15;
    Backage(WN,7,15);
    system("pause");
    return 0;
}

网友解答如下(原理相同): 动态规划求一组解,我们用f[i][j]用来表示前i件物品随意选择一些物品能够恰好装满容量为j的背包的可行性=1,不可行则为0;如果j < v[i]:f[i][j] = f[i-1][j] ,表示第i个物品的重量已经超过最大重量j了,则结果变为了前i-1件物品能否恰好装入容量为j的背包的可行性即等于f[i-1][j];

如果j>=v[i],此时就可以选择装或者不装第i件物品了,如果装入,则它的可行性就变为了前i-1前物品是否能恰好装入j-vec[i]容量的背包中可行性了;选择不装,则它的可行性变为了前i-1物品能否恰好装入容量为j的背包中可行性了,两者有一个可行,表明前i件物品就能恰好装入容量为j的背包中。f[i][j] = f[i-1][j]||f[i-1][j-vec[i]]

初始化:f[i][0]=1(i=0,1,2,,..n) 其它的f[i][j]都等于0
找出最终的一组解,用回溯就可以了。如果存在可行解,那么f[n][S]一定为1

void packageInteration(vector<int> vec, int S){
    int n = vec.size();
    int **f = new int*[n+1];
    for(int i = 0; i < n+1; i++){
        f[i] = new int[S+1];
        memset(f[i], 0, sizeof(f[i])*(S+1));
    }
    for(int i = 0; i < n+1; i++)
        f[i][0] = 1;   // 初始化
    for(int i = 1; i < n+1; i++){
        for(int j = 1; j < S+1; j++){
            if(j >= vec[i-1])
                f[i][j] = (f[i-1][j] || f[i-1][j-vec[i-1]]);
            else
                 f[i][j] = f[i-1][j];
        }   
    }
    // 回溯求结果
    int j = S;
    for(int i = n; i > 0; i--){
        if(j >= vec[i-1]){
            if(f[i][j-vec[i-1]] == 1){   // 为1 表示可行
                res.push_back(i);
                j = j - vec[i-1];
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值