一些dp进阶题

洛谷P1373 小a和uim之大逃离

题目链接
在这里插入图片描述

题目分析:

一道经典的dp题。这里的关键在于对于一种状态我们只关心两个人之间魔液之间的差值,而对他们手里具体有多少并不关心,从而大大减小时间和空间复杂度。从而dp的四个纬度分别是坐标i,j和差值以及最后拿的那个人是谁(这里也可以根据题目特性一次走两步再减少一个纬度,但因为实际上并没有优化效果故不采用)。其他还有一些需要注意的细节:①每次坐对于差值纬度都要%(k+1) ②这道题可能卡空间,大小要开得刚刚好并且不能用long long,只有最后记录结果的变量才需要long long

AC代码

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
#include <map>
#include <stack>
#include <fstream>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
int dp[805][805][20][2];
int mp[805][805];
int n,m,k;
int main()
{
    cin >> n >> m >> k;
    k++;
    memset(dp, 0, sizeof(dp));
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        {
            scanf("%d",&mp[i][j]);
            dp[i][j][mp[i][j]%k][0]=1;
        }
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            for (int p=0;p<k;p++)
            {
                dp[i][j][p][0]=(dp[i][j][p][0]+dp[i-1][j][(p-mp[i][j]+k)%k][1])%1000000007;
                dp[i][j][p][0]=(dp[i][j][p][0]+dp[i][j-1][(p-mp[i][j]+k)%k][1])%1000000007;
                dp[i][j][p][1]=(dp[i][j][p][1]+dp[i-1][j][(p+mp[i][j])%k][0])%1000000007;
                dp[i][j][p][1]=(dp[i][j][p][1]+dp[i][j-1][(p+mp[i][j])%k][0])%1000000007;
            }
    ll ans=0;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            ans=(ans+dp[i][j][0][1])%1000000007;
    cout << ans << endl;
}

洛谷P1156 垃圾陷阱

题目链接
在这里插入图片描述

题目分析:

一道比较基础的dp题,类似于01背包问题。这里可以将井的深度看作背包容量,把拥有的能量看成是价值。那么我们就能用一个一维数组来表示在某一高度上能拥有的最大能量是多少。预处理时事先按时间进行排序,每投入一个物品就进行判断能量能否支撑到该物品投入,以及投入后若用来垫脚能否到达出口。以此每次更新相应高度上最大能量最终得到结果

AC代码:

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
#include <map>
#include <stack>
#include <fstream>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
int dp[1000];
struct goods
{
    int t;
    int f;
    int h;
};
int d,g;
goods a[1000];
bool cmp(goods x,goods y)
{
    return x.t<y.t;
}
int main()
{
    cin >> d >> g;
    for (int i=1;i<=g;i++)
        cin >> a[i].t >> a[i].f >> a[i].h;
    sort(a+1, a+g+1, cmp);
    memset(dp, 0, sizeof(dp));
    dp[0]=10;
    for (int i=1;i<=g;i++)
        for (int j=d;j>=0;j--)
        {
            if (dp[j]>=a[i].t)
            {
                if (j+a[i].h>=d)
                {
                    cout << a[i].t << endl;
                    return 0;
                }
                dp[j+a[i].h]=max(dp[j+a[i].h],dp[j]);
                dp[j]+=a[i].f;
            }
        }
    cout << dp[0] << endl;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值