竞赛讨论区 > 简单dp的01背包问题
头像
HHHHHHanser
发布于 01-21 20:17
+ 关注

简单dp的01背包问题

这道题的数据n只有不到50,所以我一开始思考的是搜索,可惜记忆化学的不是很好,暴搜直接tle了,但是仍然能够拿到60分。

所以下面还是把我的搜索代码放出来:

读写换了更快的格式化输入输出,也不能过所有点,有大佬会用记忆化的可以指教一下。

#include<iostream>
#include<cstdio>
using namespace std;
int count = 0, Max = -1;
void backtracking(int startindex, int* c, int n, int beginlevel, int maxlevel) {
    if (beginlevel > maxlevel || beginlevel < 0 || startindex >= n) {
        if (startindex >= n && beginlevel <= maxlevel && beginlevel >= 0) {
            ++count;
            if (Max < beginlevel)Max = beginlevel;
        }
        return;
    }
    beginlevel += c[startindex];
    backtracking(startindex + 1, c, n, beginlevel, maxlevel);
    beginlevel -= 2 * c[startindex];
    backtracking(startindex + 1, c, n, beginlevel, maxlevel);
    beginlevel += c[startindex];
}
int main() {
    int n, beginlevel, maxlevel;
    scanf("%d %d %d", &n, &beginlevel, &maxlevel);
    int c[55] = { 0 };
    for (int i = 0; i < n; i++)scanf("%d", &c[i]);
    backtracking(0, c, n, beginlevel, maxlevel);
    if (count == 0)cout << -1;
    else cout << Max;
    return 0;
}

搜索过不了的题就只能想其他算法了。。。首先想到的就是DP了,因为这道题和以前刷过的一道目标和的问题很像,都是分别对一组数分两组,一组相加一组相减得到最后结果。

那道题的背包大小需要解一个多项式方程得到,这道题很直接,说明了背包大小是0-maxlevel,所以我们按照DP模板来直接分析:

1.确定DP数组含义:

DP数组开成DP[55][1005],典型的一维表示物品,记录状态;另一维表示背包,记录背包大小。

对于确定的i和j,DP[i][j]表示的是“状态”,即在当前状态下(选择是否装入物品i的纠结状态下,即纠结到底应该升调还是降调),是否可以通过上一音调状态升调或降调得到,如果可以得到,记录为1,不可以则记录为0.

如此,我们每个状态都是独立的,仅仅与上一状态关联,当我们把每一次变调都取舍了之后,最后一个状态就是所有我们最后可以到达的声调。

2.确定状态转移方程和遍历顺序:

按照1中理论,写出如下方程:

for(int i=1;i<=n;i++){
    for(int j=0;j<=maxlevel;j++){
        if(j-c[i]>=0&&dp[i-1][j-c[i]])dp[i][j]=1;
        if(j+c[i]<=maxlevel&&dp[i-1][j+c[i]])dp[i][j]=1;
    }
}

3.对最后的结果集分析:

最后一个结果,即DP[n]代表的就是所以可以达到的升调,我们取它最大值,只需要倒序遍历取第一个状态1即可。

下面给出我的AC代码:

#include<iostream>
using namespace std;
int main(){
    int n,beginlevel,maxlevel,max=-1;
    cin>>n>>beginlevel>>maxlevel;
    int c[55]={0},dp[55][1005]={0};
    dp[0][beginlevel]=1;
    for(int i=1;i<=n;i++)cin>>c[i];
    for(int i=1;i<=n;i++){
        for(int j=0;j<=maxlevel;j++){
            if(j-c[i]>=0&&dp[i-1][j-c[i]])dp[i][j]=1;
            if(j+c[i]<=maxlevel&&dp[i-1][j+c[i]])dp[i][j]=1;
        }
    }
    for(int i=maxlevel;i>=0;i--){
        if(dp[n][i]){
            cout<<i;
            return 0;
        }
    }
    cout<<-1;
    return 0;
}

最后偷了个懒,用了两个return 0,这种写法是不推荐的,但是我太懒了,将就着看吧。

这道题应该也可以用滚动数组来对背包进行一维空间优化,但是正如我所说的,我太懒了,所以懒得想,大家将就着想一下吧。

好了,就这样吧。

全部评论

(0) 回帖
加载中...
话题 回帖

等你来战

查看全部

热门推荐