嘘~ 正在从服务器偷取页面 . . .

洛谷P1156 垃圾陷阱 题解&浅谈刷表法与填表法


洛谷P1156 垃圾陷阱 题解&浅谈刷表法与填表法

填表法 :就是一般的动态规划,当前点的状态,可以直接用状态方程,根据之前点的状态推导出来。

刷表法:由当前点的状态,更新其他点的状态。需要注意:只用当每个状态所依赖的状态对它的影响相互独立。

下面会用一道题目给出两种写法的区别


题目链接:P1156 垃圾陷阱

题意吃垃圾就完了

卡门――农夫约翰极其珍视的一条Holsteins奶牛――已经落了到“垃圾井”中。“垃圾井”是农夫们扔垃圾的地方,它的深度为\(D(2 \le D \le 100)\)英尺。

卡门想把垃圾堆起来,等到堆得与井同样高时,她就能逃出井外了。另外,卡门可以通过吃一些垃圾来维持自己的生命。

每个垃圾都可以用来吃或堆放,并且堆放垃圾不用花费卡门的时间。

假设卡门预先知道了每个垃圾扔下的时间\(t(0< t \le 1000)\),以及每个垃圾堆放的高度\(h(1 \le h \le 25\))和吃进该垃圾能维持生命的时间\(f(1 \le f \le 30)\),要求出卡门最早能逃出井外的时间,假设卡门当前体内有足够持续\(10\)小时的能量,如果卡门\(10\)小时内没有进食,卡门就将饿死。

注:如果能量为 \(0\) 时恰好有垃圾可以吃,则不会饿死

注意到对于每个垃圾,只有吃掉和堆起来两种方法

\(dp[i][j]\) 表示只考虑前 \(i\) 个垃圾,堆到高度 \(j\) 时,最多可以活到什么时候

容易推出方程 \[ dp[i][j]=\max(dp[i-1][j]+v_i,dp[i-1][j-h_i]) \] 1.填表法

求出dp数组以后扫一遍就好了,细节较多(其实好像可以滚动数组,但是懒 qwq)

注意这里垃圾的高度可能会超过 \(m\) ,但是数据好像没卡这个东西

处理方法就是把 \(m+\max(h_i)\) 都dp一下

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(1e3+15)

struct node
{
    int h,v,t;
}a[N];
int n,m,dp[N][N];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    memset(dp,0xc0,sizeof(dp));
    dp[0][0]=10;
    cin >> m >> n;
    for(int i=1; i<=n; i++)
        cin >> a[i].t >> a[i].v >> a[i].h;
    sort(a+1,a+1+n,[](node a,node b){return a.t<b.t;});
    for(int i=1; i<=n; i++)
        for(int j=0; j<=m+25; j++)
        {
            if(dp[i-1][j]>=a[i].t)
                dp[i][j]=max(dp[i][j],dp[i-1][j]+a[i].v);
            if(j>=a[i].h&&dp[i-1][j-a[i].h]>=a[i].t)
                dp[i][j]=max(dp[i][j],dp[i-1][j-a[i].h]);
        }
    int res1=-1,res2=-1;
    for(int i=1; i<=n; i++)
    {
        for(int j=0; j<=m+25; j++)
        {
            if(dp[i][j]>=a[i].t)
                res1=max(res1,j);
            res2=max(res2,dp[i][j]);
        }
        if(res1>=m){cout << a[i].t << endl;return 0;}
    }
    cout << res2 << endl;
    return 0;
}

2.刷表法

这里可以滚动数组了,不过要两个

否则会导致数据更新错误

当然也可以不用滚动数组 位运算那么可爱为什么不写她呐?对不对?

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(1e3+15)

struct node
{
    int h,v,t;
}a[N];
int n,m,dp[2][N];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    memset(dp,0xc0,sizeof(dp));
    dp[0][0]=10;
    cin >> m >> n;
    for(int i=1; i<=n; i++)
        cin >> a[i].t >> a[i].v >> a[i].h;
    sort(a+1,a+1+n,[](node a,node b){return a.t<b.t;});
    int res=-1;
    for(int i=1; i<=n; i++)
    {
        int cur=i&1,pre=cur^1;
        memset(dp[cur],0xc0,sizeof(dp[cur]));
        for(int j=m; j>=0; j--) // 这里就不用m+25了,因为只要超出了直接就输出了
        {
            if(dp[pre][j]<a[i].t)continue;
            if(j+a[i].h>=m)return cout << a[i].t << endl,0;
            dp[cur][j+a[i].h]=max(dp[cur][j+a[i].h],dp[pre][j]);
            dp[cur][j]=max(dp[cur][j],dp[pre][j]+a[i].v);
        }
        res=max(res,dp[cur][0]);
    }
    cout << res << endl;
    return 0;
}

哼哼,我才不会说我是在考数学的时候推出来的dp方程

转载请说明出处


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录