原题目链接:B. One Bomb
题目
双十一要到了,白学姐决定清空购物车,但是不幸的是她发现即便吃土两个月也不能完成这项艰巨的任务。
贫穷的白学姐当然不能这么束手就擒,于是她决定将所有商品摆放在一张n×m地图上,地图中每个单元格可以用点 “.”(化妆品)、星号"*"(某件很贵的不可告人的商品)表示。
她决定引爆其中一件商品(既可以是化妆品,也可以是很贵的不可告人的商品),当该商品爆炸时,将会清除其所在行与列的所有商品(就像炸弹人中的十字炸弹)。
迷惑的白学姐想要确定一个唯一的引爆点,可以将所有很贵的不可告人的商品统统炸掉,但是她不知道该如何计算出这个点的坐标,希望聪明的你能为她指点迷津。
输入
第一行给出 n 和 m (1 ≤ n, m ≤ 1000) — 地图的行数和列数,n、m。
第二行开始输入整个地图,地图中每个单元格用点 “.”(化妆品)、星号 “*”(某件很贵的不可告人的商品)表示。
输出
如果你找不到这样的坐标,输出NO。
否则第一行输出YES,第二行输出这样的一个坐标x y。
注意:如果有多组解的话,输出任意一组即可。就是说你的输出和样例的输出不相同也有可能是正确的。
输入样例
Input1:
3 4
.*..
....
.*..
Input2:
3 3
..*
.*.
*..
Input3:
6 5
..*..
..*..
*****
..*..
..*..
..*..
输出样例
Output1:
YES
1 2
Output2:
NO
Output3:
YES
3 3
错误分析
看了大家的代码,果不其然,都把这个问题想的复杂化了,其实你们想一想,JerryHanson同学WA了四发就过了,说明题目其实不难,只是看你们有没有想到解题关键~~
现在给大家解答一下几种错误思路存在的问题:
-
枚举每一个坐标,计算能清除的特殊商品数量,与炸弹总数作比较。
这个思路实际上很接近答案了,但是却忽略了一个很重要的时间问题。因为地图最大是m×n(1000×1000)的,所以枚举所有坐标需要 O ( n 2 ) O(n^2) O(n2)的时间复杂度,然后再枚举这个坐标能清除特殊商品的数量需要 O ( n ) O(n) O(n)的时间复杂度,于是该算法总共需要 O ( n 3 ) O(n^3) O(n3)的时间复杂度,刚好超时,一般WA在Test 66。 -
记录每个特殊商品的坐标,依次判断
我们来看Test 50:2 2 . * * .
很容易可以发现炸弹坐标不一定就在特殊商品上。
-
特判特殊商品数量,推算其与坐标的可能关系
遗憾的是特殊商品数与坐标没关系。 -
从特殊商品所在行(列)出发,求与其他特殊商品列(行)的交集
是一种可行方案,但是还需优化判断找不到坐标的情况。 -
输出了“N0”
感谢Gentle_wind同学的精彩表演,未来继续努力,争做大家的快乐源泉。 -
特判Test 50
这是一个很巧妙的思路,可惜这个题有172个测试点,完美杜绝一切特判。
正确思路
这里给出一种简单的正确思路,考虑错误分析中第一个案例,此时计算结果已经准确无误了,那么需要对代码进行优化以减少算法的时间开销。
可以发现,在遍历所有坐标的时候再统计一次该坐标可清除的特殊商品总数是一个冗余操作,因此我们可以在建图的时候提前做好统计。
用两个数组分别存储第i行的特殊商品总数以及第j列的特殊商品总数,然后枚举所有坐标时用该数组代替原来的统计操作,这样可以将 O ( n 2 ) × O ( n ) O(n^2)×O(n) O(n2)×O(n)的时间复杂度变成 O ( n 2 ) + O ( n ) O(n^2)+O(n) O(n2)+O(n),顺利AC。
AC代码
请各位同学尽量自己独立完成,本题在算法思维及C语言应用方面能得到很好的锻炼,现在CCF认证的难度每年都在提升,为达到毕业要求,还请认真训练。
没写出来的同学看过思路后请自己编写代码,一来防止查重,二来懂思路不代表能写对程序,请务必重视。
#include<iostream>
using namespace std;
int main()
{
int row[1005]= {0},column[1005]= {0};//存行列的特殊商品总数
char map[1005][1005];//存地图
int m,n,sum=0;
cin>>m>>n;
for(int i=1; i<=m; ++i)
for(int j=1; j<=n; ++j)
{
cin>>map[i][j];
if(map[i][j]=='*')
{
row[i]++;//存行的特殊商品总数
column[j]++;//存列的特殊商品总数
sum++;//存特殊商品总数
}
}
for(int i=1; i<=m; ++i)//遍历地图每个坐标
for(int j=1; j<=n; ++j)
if(map[i][j]=='*')
{
if(sum==row[i]+column[j]-1)//行列特殊商品之和等于所有特殊商品总数
{
cout<<"YES"<<endl<<i<<" "<<j;
return 0;
}
}
else if(sum==row[i]+column[j])//行列特殊商品之和等于所有特殊商品总数
{
cout<<"YES"<<endl<<i<<" "<<j;
return 0;
}
cout<<"NO";//没有符合条件的情况
return 0;
}
提示
建议C/C++选手使用DEV、CLion、CodeBlocks或VS code,Python选手使用PyCharm,Java选手使用Eclipse或IDEA。
JetBrains全家桶可以用学生邮箱注册免费使用。