poj 1976 A Mini Locomotive(0/1背包)

点击打开链接poj 1976

思路: 0/1背包
分析:
1 题目给定n个数,要求三段连续的m个数之和最大
2 假设n个数是num[1],num[2],num[3]......num[n],那么m个连续的数可能有n-m+1种可能即num[1]+num[2]...+num[k] , num[2]+num[3]...+num[k]......

3 我们令v[1] = num[1]+num[2]...+num[k] , v[2] = num[2]+num[3]...+num[k].那么总的有n-m+1个物品每个体积为1,那么我们令dp[i][j]表示的是前i个物品放入容量为j的背包的最大值,背包的总容量为3.
那么dp[i][j]的转移方程很好写出
i >= m , dp[i][j] = max(dp[i-1][j] , dp[i-m][j-1]+v[i]);
i < m , dp[i][j] = max(dp[i-1][j] , v[i]);
怎么理解这个转移方程呢?原因就是因为这边由于每个物品是m个连续的数,所以说我们在取了第i个物品的时候很明显前面的m个物品不能取(因为数字是不能重复的)。当i < m的时候,很明显就是要么不取第i个,如果要取就是直接的v[i]。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int MAXN = 50010;

int n , m , num[MAXN];
int v[MAXN] , dp[MAXN][4]; 

int solve(){
    int sum;
    for(int i = 1 ; i <= n-m+1 ; i++){
        sum = 0;
        for(int j = i ; j <= i+m-1 ; j++)
            sum += num[j];
        v[i] = sum;
    }
    memset(dp , 0 , sizeof(dp));
    for(int i = 1 ; i <= n-m+1 ; i++){
        for(int j = 3 ; j >= 1 ; j--){
            if(i >= m)
                dp[i][j] = max(dp[i-1][j] , dp[i-m][j-1]+v[i]);
            else
                dp[i][j] = max(dp[i-1][j] , v[i]);
        }
    }
    return dp[n-m+1][3];
}

int main(){
    int Case;
    scanf("%d" , &Case);
    while(Case--){
         scanf("%d" , &n);
         for(int i = 1 ; i <= n ; i++)
             scanf("%d" , &num[i]);
         scanf("%d" , &m);
         printf("%d\n" , solve());
    }
    return 0;
}
时间: 2025-01-21 09:59:49

poj 1976 A Mini Locomotive(0/1背包)的相关文章

算法:poj 1976 A Mini Locomotive (dp 二维01背包)

题目大意: 某个车站有N个火车车厢,编号为1-N,每个车厢上有xi个人. 这个车站还有 三个火车头,他们能拉最多m个车厢(m<=N/3),而且这m个车厢的编号要连续的.问这三个火车头最多 能拉多少个人. 思路: 因为m<=N/3, 所以按照贪心的思想,为了拉更多的人,每个火车 头一定是要拉m个连续的车厢. 然后,为了求某段连续的车厢共有多少人,可以前缀和预处理, 某 一段和=sum[ i ] - sum[ i-m]. f[i][j] 代表前i个车厢,用j个火车头拉,最多能拉多少人. 对于第i个

POJ 1976 A Mini Locomotive

题意:给出n车厢以及n节车厢内的人数 现有三节迷你火车头 每个火车头可以拉连续的m节车厢 问三个火车头最多可以拉多少人. dp[i][j]表示第i节车厢有j个车头可以拉的总人数 dp[i][j]=max(dp[i-1][j],dp[k][j-1]+a[i]-a[k]) k=max(i-m,0) 前一个表示该节车厢不拉 后一状态表示加一个火车头拉 #include <iostream> #include<cstdio> #include<cstring> using na

poj 3624 Charm Bracelet (0/1背包)

点击打开链接 裸0/1背包 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int MAXN = 15000; int n , m; int w[MAXN] , v[MAXN] , dp[MAXN]; int main(){ while(scanf("%d%d" , &n , &

poj 1948 Triangular Pastures(二维0/1背包)

点击打开链接poj 1948 思路: 二维0/1背包 分析: 1 题目要求从n个木棒里面选出m个组成一个三角形,使得三角形的面积最大 2 对于三角形来说知道了两条边和周长就可以求面积,按照0/1背包的思想dp[i][j][k]表示前i个木棒能否组成第一条边为长度j,第二条长度为k.如果dp[j-v[i]][k] 或dp[j][k-v[i]] 为true则dp[j][k]就为true 3 我们求出了所有可能的组合之和,就去枚举所有的边长的情况,然后求最大的面积 代码: #include<cmath

poj 3211 Washing Clothes(0/1背包)

点击打开链接poj 3211 思路: 0/1背包 分析: 1 题目要求洗完n件衣服所需的最少的时间,并且必须洗完一种颜色才能跳到下一种 2 仔细想想这一题和uva上面的一道分金币非常的相似,由于要求必须洗完一种颜色才能跳到下一种,那么我们只要使得洗每一种颜色的时间最少那么总的就最少,那怎样才能够最少的时间呢?也就是要求两个人的时间差最小(也就相当于一个人用一半的时间去能够洗的最多的衣服),那么就转化为0/1背包的思想 3 做m次的dp然后求和即可 代码: #include<cstdio> #i

hdu 2955 Robberies(0/1背包)

点击打开链接hdu 2955 思路: 0/1背包 分析: 1 按照题目的意思我们很容易知道这就是一个0/1背包问题,如果我们把概率当作是背包的容量,那么我们遇到一个问题就是浮点数的dp,因为题目没有告诉我们小数点具体几位,那么我们就不能够通过乘上10^n来转化为整数,所以我们应该考虑换种思想 2 按照正常的思路是dp[i][j]表示前i个物品放入概率为j的最大价值,那么我们这边把价值当成背包来看的话我们设dp[i][j]表示前i个物品放入金钱为j的最小被抓概率(因为题目不好求最小概率我们可以认为

hdu 3466 Proud Merchants(0/1背包)

点击打开链接hdu 3466 思路: 0/1背包 分析: 1 这一题和"hdu2546 饭卡"有点像,但是又有不同,不同的是这一题每一个物品都有一个限制的值Q[i],求最大的价值 2 题目明确提到每一种物品只能卖一次或这不卖,那这明显就是0/1的性质,但是现在多了一个条件钱不能少于Q[i].这边的话我各种YY无果之后,果断看了题解,发现是要按照q-p排序,然后再做dp. 3 经过一番的YY之后,我明白了为什么按照q-p是正确的.我们都知道dp有一个很重要的特点就是无后效性,如果没有金钱

hdu 2639 Bone Collector II (0/1背包)

点击打开链接hdu 2639 思路: 0/1背包求第k优解 分析: 1 其基本思想是,将每个状态都表示成有序队列,将状态转移方程中的 max/min 转 化成有序队列的合并. 2 这里仍然以 01 背包为例讲解一下.    首先看 01 背包求最优解的状态转移方程: F [i, v] = max{F [i − 1, v], F [i − 1, v −Ci ] + Wi }.如果要求第 K 优解,那么状态 F [i, v] 就应该是一个大小为 K 的队列F [i, v, 1 . . . K].其中

uva 562 Dividing coins (0/1背包)

点击打开链接uva 562 思路: 0/1背包 分析: 1 题目意思是有两个人分n个金币,要求最后两个人的金币差值最小 2 我们利用背包的思想即背包的总容量为金币总和的一半,去求出可以放入背包的最大的金币(这里其实就是某一个人能获得的最大的金币),那么最后的ans就是(sum-dp[sum/2])-dp[sum/2] 代码: #include<cstdio> #include<cstring> #include<iostream> #include<algorit