Description
一天,淘气的Tom不小心将水泼到了他哥哥Jerry刚完成的作文上。原本崭新的作文纸顿时变得皱巴巴的,更糟糕的是由于水的关系,许多字都看不清了。可怜的Tom知道他闯下大祸了,等Jerry回来一定少不了一顿修理。现在Tom只想知道Jerry的作文被“破坏”了多少。Jerry用方格纸来写作文,每行有L个格子。(左图显示的是L = 10时的一篇作文,’X’表示该格有字,该文有三个段落)
右图显示的是浸水后的作文 ,’O’表示这个位置上的文字已经被破坏。可是Tom并不知道原先哪些格子有文字,哪些没有,他唯一知道的是原文章分为M个段落,并且每个段落另起一行,空两格开头,段落内部没有空格(注意:任何一行只要开头的两个格子没有文字就可能是一个新段落的开始,例如右图中可能有4个段落)
Tom想知道至少有多少个字被破坏了,你能告诉他吗?
Input
多组用例,每组用例第一行为三个整数n,l和m分别表示行数,每行字数以及段数,之后为以n*l矩阵表示这张作文纸,以文件尾结束输入
Output
对于每组用例,输出与至少被破坏的字数
Sample Input
10 10 3
0 0 0 1 1 1 0 1 1 0
1 1 0 0 0 1 1 1 0 0
0 0 1 1 0 0 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 0 1 0 1 1 1 0 0 0
1 1 0 0 1 1 1 1 1 1
1 1 1 1 1 1 1 0 0 0
0 0 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
0 0 0 0 1 1 1 1 1 0
Sample Output
19
Solution
如果某行有成为一段首行的“潜质”,即此行前两格为0的话,那么其上一行的末尾0就可以当做没有字,因此我们首先统计所有被破坏的字数ans,然后减去2*m(每段前两格没有字),之后统计每个可能作为段首行的行前一行末尾0的个数,对其排序后选取前m-1个从ans中减掉,然后再减去最后一行末尾0的个数(最后一行必然是作为最后一段的最后一行)即可
Code
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 11111
#define maxl 111
int n,l,m;
int map[maxn][maxl];
int cmp(int a,int b)
{
return a>b;
}
int main()
{
while(~scanf("%d%d%d",&n,&l,&m))
{
int ans=0,k=0;
int cnt[maxn]={0};//记录每个可能成为新段落的行前一行末尾0的个数
for(int i=0;i<n;i++)
for(int j=0;j<l;j++)
{
scanf("%d",&map[i][j]);
if(!map[i][j]) ans++;//统计0的个数
}
for(int i=1;i<n;i++)
if(!map[i][0]&&!map[i][1])
{
for(int j=l-1;j>=0;j--)
if(!map[i-1][j]) cnt[k]++;
else break;
k++;
}
for(int j=l-1;j>=0;j--)//最后一行必然是最后一段的结尾故末尾的0可以减去
if(!map[n-1][j]) ans--;
else break;
sort(cnt,cnt+k,cmp);//对0的个数降序排序
for(int i=0;i<m-1;i++)
ans-=cnt[i];
printf("%d\n",ans-2*m);//每段前两个0也要减去
}
return 0;
}