HDU 4517 小小明系列故事---游戏的烦恼 (模拟题)
问题描述 :
小小明最近在玩一款游戏,它由n*m大小的矩阵构成,矩阵上会随机产生一些黑色的点,这些点它们可能会连在一起也可能会分开,这些点的个数没有限制,但是每个1*1方格中最多只可能有一个黑点产生。游戏要求玩家以最短的时间用x*y的小矩阵覆盖这个大矩阵,覆盖的要求有以下2点: 1. x*y大小的小矩阵内必须有x*y个黑点。 2. 多个小矩阵可以重叠,但是每个小矩阵放置的位置必须是独一无二的,即不同的小矩阵内的黑点不能完全相同。例如1*2的矩阵可以横着放,也可以竖着放,这两种方法是不同的,即使它们可能共用黑点。 小小明是个粗心的孩子,他尝试了很多遍都无法将所有的符合要求的小矩阵找到,聪明的你,能不能告诉烦恼中的小小明这个大矩阵里有多少个满足要求的小矩阵呢?
输入:
题目有多组测试数据(不多于100个); 每组测试数据的第一行包含2个正整数n和m,然后第二行是x和y(n,m,x,y的意思如题),接下来n行,每行m个字符,其中’ * ’表示黑点,’ . ’表示空白。 n和m为0则结束输入。
0 < n, m <= 2000
0 < x, y <= 1000
输出:
题目有多组测试数据(不多于100个); 每组测试数据的第一行包含2个正整数n和m,然后第二行是x和y(n,m,x,y的意思如题),接下来n行,每行m个字符,其中’ * ’表示黑点,’ . ’表示空白。 n和m为0则结束输入。
0 < n, m <= 2000 0 < x, y <= 1000
样例输入:
2 3
1 2
**.
.**
0 0
样例输出:
3
解题思路:
(1)、用cnt[ i ][ j ]记录以第i行第j列为终点,向左连续带*号的的长度;
(2)、再从上到下按列处理一次,
(3)、用len1,len2记录以第i行第j列为终点时候,每一行带*号的长度大于等于规定的长/宽的数目。
(4)、相加就是答案。这里有个陷阱,就是当小矩阵行等于列的时候,要将答案除以2。
1 #include<iostream>
2 #include<cstring>
3 #include<cstdio>
4 #include<algorithm>
5 using namespace std;
6 #define N 2005
7 int cnt[N][N];
8 int main()
9 {
10 int i,j,n,c,r,m;
11 char ch[N];
12 while(scanf("%d%d",&n,&m) && n + m)
13 {
14 scanf("%d%d",&c,&r);
15 int ans = 0;
16 for(i = 1;i <= n;i++)
17 {
18 scanf("%s",&ch);
19 for(j = 1;j <= m;j++)
20 {
21
22 int flag = ch[j - 1] == '*'?1:0;
23 // cout<<ch[j - 1]<<endl;
24 if(flag)
25 cnt[i][j] = cnt[i][j - 1] + 1;
26 else
27 cnt[i][j] = 0;
28
29 }
30 }
31 int len1,len2;
32 for(i = 1;i <= m;i++)
33 {
34 len1 = len2 = 0;
35 for(j = 1;j <= n;j++)
36 {
37 // cout<<cnt[j][i]<<endl;
38 if(cnt[j][i] >= c) len1++;
39 else len1 = 0;
40 if(len1 >= r)
41 {
42 ans ++;
43 }
44 if(cnt[j][i] >= r) len2++;
45 else len2 = 0;
46 if(len2 >= c)
47 {
48 ans++;
49 }
50 }
51 }
52 if(c == r)
53 ans /= 2;
54 printf("%d\n",ans);
55 }
56 return 0;
57 }