题面:
输入第一行包含一个整数 q (1 ≤ q ≤ 5 * 10^4) — 表示测试组数
对于每组数据:
第一行有两个整数 n 和 m (1 ≤ n, m ≤ 5 * 10^4, n * m ≤ 4 * 10^5) — 表示网格图的行数和列数
接下来的 n 行中每一行包含 m 个字符 — ‘.’ 表示这个格子是白色的, '’ 表示这个格子是黑色的
保证 q 组数据中 n 的总和不超过 5 * 10^4, nm 的总和不超过 4 * 10^5
答案输出 q 行, 第 i 行包含一个整数 — 表示第 i 组数据的答案
sample input:
9
5 5
..*..
..*..
*****
..*..
..*..
3 4
****
.*..
.*..
4 3
***
*..
*..
*..
5 5
*****
*.*.*
*****
..*.*
..***
1 4
****
5 5
.....
..*..
.***.
..*..
.....
5 3
...
.*.
.*.
***
.*.
3 3
.*.
*.*
.*.
4 4
*.**
....
*.**
*.**
sample output:
0
0
0
0
0
4
1
1
2
思路:
- 因为只需要实现一个十字架即可,所以只需要进行整个数组的遍历然后进行最小值寻找即可
- 需要注意他的数据范围,看二位数组来记录肯定会爆掉。我是用两个一维数组分别来描述行和列,刚开始TLE是因为const int 了一个三个数组都不会爆掉的最大范围,用来定义三个数组,结果超时了。对三个数组分别定义最大值就能AC
- 遍历所有点,计算以它为中心产生的十字架需要补多少,如果它本身是白的话,需要 -1,因为被计算了两次,最后输出最小值
- 想要复杂度更低的话,应该寻找行列中的空白最小值然后看两个相交后需要补充的位置数,但由于他们不一定相交的位置恰好是空白点,并且最大行列不一定只有一个,记录方法上需要细想
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
//const int N=4e5+1;
int a[50001];
int b[50001];
char mul[400001];
const int INF=1e9;
int main()
{
int q,n,m;
scanf("%d",&q);
while(q--)
{
scanf("%d %d",&n,&m);
int count=0;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>mul[count];
if(mul[count]=='.')
a[i]++,b[j]++;
count++;
}
}
int ans=INF;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
int temp=a[i]+b[j];
if(mul[i*m+j]=='.')
temp--;
if(temp==0)//如果为0说明找到不需要再填
{
ans=0;
break;
}
ans=min(ans,temp);
}
}
cout<<ans<<endl;
}
return 0;
}