dp练习赛2

倒着来

T4:背包问题

一看题就知道是背包————————————

问题描述
从T组物品中选出一些物品,放入背包中,求剩余空间的最小值。
限制条件:从每组物品中挑选物品必须要选取连续的一段。就是说,如果这组物品共有n个: 物品1、物品2、物品3、…、物品n,那么只能选取物品i、物品i+1、…、物品j,其中1<=i<=j<=n,或者不选。
输入
第一行为两个用空格隔开的正整数v和T。表示背包的空间和物品的组数。接下来有T行,每行先是一个正整数ni,表示这组物品有ni个,然后ni个正整数,表示每个物品的大小。
输出
仅一个数,表示剩余空间的最小值。
样例输入
100 3
3 7 6 8
2 80 70
4 101 108 103 150
样例输出
6
【样例说明】 第1组选6、8,第2组选80,第3组不选。
【限制】
60%的数据满足:1 <= ni <= 10
100%的数据满足:1 <= ni <= 100,1<=v<=5000,1<=T<=10

显而易见的分组背包,无非是背包中的物品必须连续选择,根据这个条件可以想到每一组中可以选的值是组内物品前缀和中的一个,索性就把前缀和当作组中物品,进行预处理后,做分组背包就好了。
over

T3:贝茜的派

Description
Bessie has broken into Farmer John’s house again! She has discovered a pile of lemons and a pile of oranges in the kitchen (effectively an unlimited number of each), and she is determined to eat as much as possible.
Bessie has a maximum fullness of T (1≤T≤5,000,000). Eating an orange increases her fullness by A, and eating a lemon increases her fullness by B (1≤A,B≤T). Additionally, if she wants, Bessie can drink water at most one time, which will instantly decrease her fullness by half (and will round down).
Help Bessie determine the maximum fullness she can achieve!
奶牛Bessie潜入了农夫约翰的家,她发现这里有无穷无尽的柠檬派和橘子派。
Bessie的饱胀值一开始是0,且上限是T,每个柠檬派可以提供A点饱胀值,每个橘子派可以提供B点饱胀值。
Bessie可以不断地吃东西,如果她的饱胀值没有超出T的话。同时,Bessie有一次喝水的机会,喝完后,她的饱胀值将减少一半(往下取整)。
请计算出Bessie的饱胀值最多可以达到多少。
Input
The first (and only) line has three integers T, A, and B.
Output
A single integer, representing the maximum fullness Bessie can achieve.
Sample Input
8 5 6
Sample Output
8

这题很明显是一道完全背包,只是在做完一次后可以喝水(V减少一半),这对做完全背包并不存在影响,只需要多处理一次,用bool数组存贮第一次出现过的V以及每个质量都喝水后的V/2,再基于处理后的bool数组再做一次完全背包就可以了。

    t=read();
    a=read();
    b=read();
    f[0]=1;
    for(int i=0;i<=t;i++)
    {
        if(f[i]) f[i+a]=1,f[i+b]=1;
        f[i/2]=f[i/2]||f[i];
    }
    for(int i=0;i<=t;i++)
    {
        if(f[i]) f[i+a]=1,f[i+b]=1;
    }
    for(int i=t;i>=1;i--)
    if(f[i]) {cout<<i<<endl;return 0;}
    return 0;

T2:养猪

这题我怕DP会友后效性,又想不到如何去除后效性,就想到了贪心,本想贪心应该能处理n==k的情况的,没想到写了个暴力DFS后,被拍死了,还花了老半天时间,不过还是有点用的,至少知道了怎么对拍。。。

Description
你有一个猪圈,有N头猪,每天你最多可以杀一头猪卖钱,收益就是猪的体重。但是每过一天猪的体重都会下降Pi,问K天内你的最大获利。
Input
第一行两个正整数N、K;
第二行N个数表示猪的初始重量A[i];
第三行N个数表示P[i];
Output
一行一个整数表示最大的获利。
Sample Input
2 2 10 10 1 2
Sample Output
19
Hint
20% 数据满足 1≤N≤20
100%数据满足1≤N≤1000, 体重≤105。

但好像DP方程就是我所想的那样。用 i 表示第i头猪, j 表示 前 i-1头猪杀了几头的所获得的利益最大值,DP转移就是由 i-1头猪杀j头和i-1头猪杀j-1头的利益加上杀了第i头的总价值。

但这道题还需要排序,并不是很清楚原因,貌似是一个贪心的思想,还有就是最后的DP[n][k]并不一定是最大值

T1:马拉松

【问题描述】
奶牛们浑身难受,有感于此,FJ让他的奶牛们参与了各种各样的体育锻炼活动;
他珍爱的贝茜参加了一个跑步培训班,她最终预计要跑一个马拉松,从FJ农场附近的城市中心到FJ的农场;
这场马拉松包含N个逐一通过的检查点,检查点1是起点,检查点N是终点。
贝茜被要求一个接一个的通过所有检查点,但是作为一只懒惰的母牛,她有k次机会去跳过某个检查点来缩短她马拉松的路程。她不能跳过检查点1或检查点N,理所应当的,这种放肆显然会被发现的;
请帮助贝茜找到一个最小的距离,在她跳过某个检查点后。
注意比赛设置的检查点是在城市的一个个网格中,设第一个检查点坐标为(x1,y1),第二个为(x2,y2),它们之间的距离是通过|x1-x2| + |y1-y2|这个公式来计算的。这种测量距离的方法—通过x之间的差的绝对值加上y之间差的绝对值,有时被称为曼哈顿距离,因为它反映出了一个在市中心网格的事实,你可以平行于x轴抑或y轴走,但是你绝对不能斜着走一条直线。
(良心总结:在二维平面上有N个点,从(x1,y1)到(x2,y2)的代价为|x1-x2|+|y1-y2|。
求从1号点出发,按从1到N的顺序依次到达每个点的最小总代价。
你有K次机会可以跳过某个点,不允许跳过1号点或N号点。)
【输入】
第一行给你一个N的值和k次跳过的机会
接下来的N行,每行含有两个以空格隔开的整数,x和y代表一个检查点((-1000 <= x <= 1000, -1000 <= y <= 1000) 。给出的检查点是必须去通过的。
注意,路程中可能会跨越某个点几次,几个检查点可能会出现在同一个实际的位置上。
在这种检查点上,贝西只能跳过一个检查点,而非这个位置上的全部检查点。
【输出】
输出贝茜在跳过某个检查点后跑的最短路程。不要忘记在输出结束的时候输出一个换行。
在这个示例中,跳过检查点(8,3)和(10.-5)可以得到最短的距离4.
【输入样例1】
5 2
0 0
8 3
1 1
10 -5
2 2
【输出样例1】
4
【数据范围】
3<=k

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int sum=0;
    int f=1;
    char c=getchar();
    for(;c>'9'||c<'0';c=getchar())
    if(c=='-') f=-1;
    for(;c>='0'&&c<='9';c=getchar())
    sum=(sum<<3)+(sum<<1)+c-48;
    return sum*f;
}
int n,k;
int a[512],b[512];
int dp[512][512];
int d(int q,int w)
{
    return (abs(a[q]-a[w])+abs(b[q]-b[w]));
}
int main()
{
    n=read();
    k=read();
    for(int i=1;i<=n;i++)
    a[i]=read(),b[i]=read();
    memset(dp,10,sizeof(dp));
    dp[1][0]=0;
    for(int i=2;i<=n;i++)
    {
        for(int j=0;j<=min(i-2,k);j++)
        {
            for(int k=i-j-1;k<i;k++)
            {
                dp[i][j]=min(dp[i][j],dp[k][j-(i-k-1)]+d(k,i));
            }
        }
    }
    cout<<dp[n][k];
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值