背包的变形(一般都是要满足在什么条件下,需要什么值最大或者最小 那么就可以跑一下背包)

链接:https://ac.nowcoder.com/acm/contest/893/H
来源:牛客网

在Casya生活的世界里,一天由m个小时组成。
最近Casya的女神终于答应在接下来的n天中与Casya聊天,Casya非常激动。

在这n天中的每一天的每一个小时中女神可能会在线或者不在线,
某个小时如果女神如果在线且Casya在线的话他们就会开心的聊一个小时;
反之如果女神在线Casya没有在线的话女神就会认为Casya放了她的鸽子而积累一点生气度。

而Casya是个很懒惰的人,他每天只愿意上线一次,当他某天下线后就不愿意再上线了。
换句话说,他每天在线的时间必须是连续的。

现在Casya已经知道每一天的每个小时女神是否会在线

Casya希望在这n天中女神的总生气度不超过k,在此前提下Casya希望他的总上线时间最小。
假设每个小时Casya和女神要么完整在线要么完整不在线,请问Casya在这n天中最小的总上线时间是多少小时?

这题就出现了 在不超过k条件下 上线时间最小 那么就可以想到背包了 上线时间小对立的就是下线时间最大 那么就是一个背包问题了 在背包容量为k的情况下 尽量的让我下线时间最大 分组背包搞一下就好了

注意s.size() 这个读入string就很坑 尽量不要用size()这个函数

还有个坑点就是这题不能用滚动数组 因为这个物品的重量可能是0 如果滚动数组了就炸了 因为分组的话你就把自己这个组的0给算进去了 f[j] 还是f[j] 就算进去的 就老老实实二维背包一下就好了 还有我上线时间是可以为0的 也就是我不上线 这个预处理也很关键啊啊啊
说多了都是细节 背包读入一般就从1开始读入 这个要非常注意啊啊啊啊 边界问题很关键

多组数据一定要记得数组 vector 之类的初始化一下

下面是代码

#include<bits/stdc++.h>

using namespace std;

const int maxn = 210;
int f[maxn][maxn];
struct node{
    int v;
    int w;
};

vector<node> goods[maxn];

int main()
{
    int t,sum[maxn];
    scanf("%d",&t);
    while(t--)
    {
        memset(f,0,sizeof(f));
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        string s;
        for(int i = 1; i <= n; i++)// 第i填
        {
            cin>>s;
            sum[0] = 0;
            int len = m;// s.size() 有毒
            for(int j = 1; j <= len; j++)
            {
                int ch = s[j-1] - '0';
                sum[j] = sum[j-1] + ch;
            }
            for(int ll = 0; ll <= len; ll++) // 上线时间 给
            {
                int t_min = 1000;
                for(int p = 1; p <= len; p ++)
                {
                    if((p + ll - 1) > len) break;
                    else t_min=min(t_min,sum[len] - (sum[p + ll - 1] - sum[p-1]));
                    //cout<<"t    "<<t_min;
                }
                //cout<<endl;
                goods[i].push_back({t_min ,len - ll}); //  同一时间下的不在线时间  女神最小生气度 //为0 的时候特判一下 然后加入到最后一个数组里面
            }
        }
        for(int i = 1; i <= n; i++)// 分组背包一下 f[i][j] 表示 物品为i 体积为j是的最大值
        {
            for(int j = 0; j <= k; j++)
            {
                for(int pp = 0; pp < goods[i].size(); pp++)
                {
                    if(j >= goods[i][pp].v)
                    {
                        f[i][j] = max(f[i-1][j - goods[i][pp].v] + goods[i][pp].w,f[i][j]);
                    }
                }
            }
        }
        int res = 0;
        for(int i = 1; i <= n; i++) res = max(res,f[i][k]);
        cout<<n*m - res<<endl;
        for(int i = 1; i <= n; i++) goods[i].clear();// 记得重新清零一下
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值