链接: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;
}