题目
描述
你是一个大学的学生,你有 n个长度为 m 的字符串,表示你 n 天的课程安排以及每天有m个小时。
字符为 1 表示你需要上这节课,字符为 0 表示你不需要上这节课。假如每天你的第一堂课是在第 i 个小时,而最后一堂课是在第 j 个小时,那么你在这一天会在大学里花 j- i + 1 个小时。如果某天没有课程,那么你会呆在家里,因此要花 0 个小时在大学里。
但是你不喜欢在学校,所以你可以最多逃掉 k节课(你可以任意安排逃掉哪些课,但不能超过 k 节),求你在学校的最少时间。
输入
第一行包含三个整数 n,m和 k( 1≤n,m≤500,0≤k≤500),天数、每天的工作小时数以及你可以逃课的次数。
然后,n 行,第 i 行包含 m 个字符的二进制字符串。如果第 i 行中的第 j 个字符为 1 ,则你在第 i 天的第 j 个小时有一个课程(如果为0,则没有此类课程)。
输出
打印一个整数–表示你在学校的最少时间
样例
输入
2 5 1
01001
10110
输出
5
提示
【样例解释】
你可以逃掉第一天的最后一节课,这样你第一天在学校 11 小时,第二天在学校 44 小时,答案为 55 小时
【数据说明】
对于30%的数据: 1 ⩽ n , m ⩽ 10 1 \leqslant{n,m}\leqslant10 1⩽n,m⩽10
对于60%的数据: 1 ⩽ n , m ⩽ 100 1 \leqslant{n,m}\leqslant100 1⩽n,m⩽100
对于100%的数据: 1 ⩽ n , m ⩽ 500 1 \leqslant{n,m}\leqslant500 1⩽n,m⩽500
分析
令 num[i][j] 代表第 i 天的翘 j 节课的的最小在校时间
令 dp[i][j] 代表前 i 天翘 j 节课的最小在校时间
num[i][j]可以用三层for循环暴力求解
dp[i][j]=min(dp[i][j]=min(dp[i-1][j-o]+num[i][o])
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll dp[600][600],num[600][600];
vector<int>v[600];
void solve()
{
ll n,m,k,i,j;
cin>>n>>m>>k;
for(i=1;i<=n;i++)
{
char ch[600];
cin>>ch;
for(j=0;j<m;j++)//取出为1的下标
{
if(ch[j]=='1') v[i].push_back(j);
}
}
for(i=1;i<=n;i++) //num[i][j]表示第i天翘j门课的最少在校时间
{
int tmp=v[i].size();
for(int len=1;len<=tmp;len++)//len代表上课的门数
{
int mm=v[i][tmp-1]-v[i][0]+1;
for(j=0;j+len-1<tmp;j++)
{
mm=min(mm,v[i][j+len-1]-v[i][j]+1);
}
num[i][tmp-len]=mm;
}
}
//dp[i][j]代表前i天翘j门课的最小在校时间
//dp[i][j]=min(dp[i-1][j-o]+num[i][o])
for(i=1;i<=n;i++) dp[i][0]=dp[i-1][0]+num[i][0];//初始化翘0节课的在校时间
for(i=1;i<=n;i++)
{
for(j=1;j<=k;j++)
{
ll mm=0x3f3f3f3f;
for(int o=0;o<=j;o++)
{
mm=min(mm,dp[i-1][j-o]+num[i][o]);
}
dp[i][j]=mm;
}
}
cout<<dp[n][k]<<endl;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
//cin>>t;
while(t--)
{
solve();
}
return 0;
}