科技庄园(背包dp)---对于蒟蒻来说死了一大片的奇题

题目描述:

Life种了一块田,里面种了一些桃树。

Life对PFT说:“我给你一定的时间去摘桃,你必须在规定的时间之内回到我面前,否则你摘的桃都要归我吃!”

PFT思考了一会,最终答应了!

由于PFT的数学不好!它并不知道怎样才能在规定的时间获得最大的价值,

由于PFT不是机器人,所以他的体力并不是无限的,他不想摘很多的桃以至体力为0,而白白把桃给Life(如果体力为0,刚刚好回到Life的地点是不行的)。同时PFT每次只能摘一棵桃树,,每棵桃树都可以摘K次(对于同一棵桃每次摘的桃数相同)。每次摘完后都要返回出发点(PFT一次拿不了很多)即Life的所在地(0,0){试验田左上角的桃坐标是(1,1)}。

PFT每秒只能移动一个单位,每移动一个单位耗费体力1(摘取不花费时间和体力,但只限上下左右移动)。

 

输入格式:

第一行:四个数为N,M,TI,A 分别表示试验田的长和宽,Life给PFT的时间,和PFT的体力。

下面一个N行M列的矩阵桃田。表示每次每棵桃树上能摘的桃数。

接下来N行M列的矩阵,表示每棵桃最多可以采摘的次数K。

 

输出格式:

一个数:PFT可以获得的最大的桃个数。

 

样例输入:

4 4 13 20
10 0 0 0
0 0 10 0
0 0 10 0
0 0 0 0
1 0 0 0
0 0 2 0
0 0 4 0
0 0 0 0

样例输出:

10

思路:(多重背包+二进制优化)的加强版。由于PFT只能走直线,所以当PFT的位置在(i,j)时,PFT到起点的距离是i+j。
又因为PFT的体力与PFT的时间缺一不可,所以只要在时间与体力-1之间取较小值即可。注意:当体力=0时,回到起点是不行的,所以要体力-1。


二进制优化(重点):

for(int j=1;j<=m;j++){
    cin>>s;
    int t=1,x=2*(i+j);
    if(l[i][j]);{
        while(s>=t) {
            c[++q]=t*x;
            v[q]=t*l[i][j];
            s-=t;
            t*=2;//拆成1,2,4,8,16的形式 
        }
        c[++q]=x*s;
        v[q]=s*l[i][j];
    }
}
//只要s>=t,则还可以再拆,于是t乘2,s减少t。
 
 

上代码(改进过的):

 

#include<bits/stdc++.h>
using namespace std;
long long n,m,v[100000],c[100000],l[1000][1000],k[100000],t,e,q,s;
int main() {
    cin>>n>>m>>t>>e;
    for(register int i=1; i<=n; i++) for(register int j=1; j<=m; j++)cin>>l[i][j];
    for(register int i=1; i<=n; i++) // register,寄存器,可以加速 
        for(register int j=1; j<=m; j++) {
            cin>>s;
            int t=1,x=2*(i+j);
            if(l[i][j]){//二进制优化 
                while(s>=t) {
                    c[++q]=t*x;
                    v[q]=t*l[i][j];
                    s-=t;
                    t*=2;
                }
                c[++q]=x*s;
                v[q]=s*l[i][j];
            }
        }
    t=min(t,e-1);
    for(register int i=1;i<=q;i++)for(register int j=t;j>=c[i];j--)k[j]=max(k[j],k[j-c[i]]+v[i]);//01背包就可以了 
    cout<<k[t];
    return 0; 
}
View Code

 

 

转载于:https://www.cnblogs.com/YFbing/p/9580396.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值