在一个 n×m 的方格地图上,某些方格上放置着炸弹。手动引爆一个炸弹以后,炸弹会把炸弹所在的行和列上的所有炸弹引爆,被引爆的炸弹又能引爆其他炸弹,这样连锁下去。
现在为了引爆地图上的所有炸弹,需要手动引爆其中一些炸弹,为了把危险程度降到最低,请算出最少手动引爆多少个炸弹可以把地图上的所有炸弹引爆。
输入格式
第一行输两个整数 n, m,用空格隔开。
接下来 n 行,每行输入一个长度为 m 的字符串,表示地图信息。0表示没有炸弹,1表示炸弹。
数据约定:
对于60% 的数据: 1≤n,m≤100;
对于 100% 的数据: 1≤n,m≤1000;
数据量比较大,不建议用cin输入。
输出格式
输出要手动引爆的炸弹数。
1.看到这道题我的思路是首先我需要确定炸弹的个数,以及每个炸弹所对应的坐标,由于用到横纵坐标两个参数,所以考虑决定选用结构体构建炸弹的点.
2.根据题目给定的要求需要以字符串,所以决定采用字符数组更为合理,char类型,即输入采用二维数组,根据所给定的m,n进行。
3.对于每一颗炸弹,他均有两个参数,分别是行号和列号,对于所有的炸弹遍历我们将按照,横纵坐标任意一个值相同我们将他们连接起来,然后我们将炸弹形成连通图
4.对于不同的炸弹不同的老大大大哥,所以将这些炸弹的大哥哥,放入栈内,最后去重,得到的vector长度即为最终的最优答案
#include
#include
#include
#include
using namespace std;//首先记录 炸弹即 1 存在的位置坐标
#define Max 1000
char a[Max][Max];//每行可以容纳的数量
int pre[Max];
int k = 0;
struct Node
{
int x;
int y;
}p[100];//100个炸弹点
int find(int x)
{
int r = x;
while (r != pre[r])
r = pre[r];
int i = x, j;
while (i != r)//路径压缩
{
j = pre[i]; // 在改变上级之前用临时变量 j 记录下他的值
pre[i] = r; //把上级改为根节点
i = j;
}
return r;
}
int main()
{
vector<int> elem;
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
cin >> a[i][j];
if (a[i][j] == '1')//记录炸弹,并且统计炸弹的个数
{
k++;
p[k].x = i;
p[k].y = j;
}
}
}
//炸弹的初始化,设置他们的前驱结点均为自己
for (int i = 1; i <= k; i++)
{
pre[i] = i;
}
//如果任意两个炸弹的 横或者纵坐标相同则连接两个点
for (int i = 1; i <= k; i++)
{
for (int j = i + 1; j <= k; j++)
{
if (p[i].x == p[j].x || p[i].x == p[j].y)
{
pre[j] = i;
}
}
}
//将每个炸弹的大大大哥找到,压入栈内
/*记录每个1的坐标然后对相同的坐标进行爆破,行坐标相同直接爆破,纵坐标相同直接爆破*/
for (int i = 1; i <= k; i++)
{
elem.push_back(find(i));
}
//排序
sort(elem.begin(), elem.end());
elem.erase(unique(elem.begin(), elem.end()),elem.end());//unique()函数将重复的元素放置在最后
//erase将重复的第一个元素开始,到最后一个元素开始,全部擦除
cout << elem.size() << endl;//数字的种类既是最终的答案
/*
for (int i = 1; i <= k; i++)//前驱验证
{
cout << "第" << i << "个的前驱" << pre[i] << endl;
}*/
/*得到最终的炸弹个数*/
//cout << k << endl;
return 0;
}
欢迎大家与我交流,并提出意见和建议,我将进行进一步优化和处理