在一个 n×m 的方格地图上,某些方格上放置着炸弹。手动引爆一个炸弹以后,炸弹会把炸弹所在的行和列上的所有炸弹引爆,被引爆的炸弹又能引爆其他炸弹,这样连锁下去。
现在为了引爆地图上的所有炸弹,需要手动引爆其中一些炸弹,为了把危险程度降到最低,请算出最少手动引爆多少个炸弹可以把地图上的所有炸弹引爆。
输入格式
第一行输两个整数 n, m,用空格隔开。
接下来 n 行,每行输入一个长度为 m 的字符串,表示地图信息。0表示没有炸弹,1表示炸弹。
数据约定:
对于60% 的数据: 1≤n,m≤100;
对于 100% 的数据: 1≤n,m≤1000;
输入:
5 5
00010
00010
01001
10001
01000
输出:
2
import java.util.Scanner;
/*遍历得到的第一个炸弹作为根节点; */
public class 引爆炸弹 {
static int[] pre;
static int ans;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int m = input.nextInt();
String[] map = new String[n];
int row[] = new int[n];
int colum[] = new int[m];
pre = new int[1004];
for (int i = 0; i < pre.length; i++) {
pre[i] = i;//每个炸弹的父节点都是自己,pre[i]储存第i个炸弹的父节点
}
int count = 0;
int ans = 0;
for (int i = 0; i < n; i++) {
map[i] = new String(input.next());
for (int j = 0; j < m; j++) {
if (map[i].charAt(j)=='1') {//这里是炸弹
count++;//count代表第几个炸弹
pre[count]=count;
if (row[i]==0) {//这里还未被炸弹引爆过
row[i]=count;//说明第i行的父节点是count;被第count个炸弹引爆
}else {
join(row[i],count);//第i行属于第row[i]个炸弹引爆,
//明显应该和count是一个根节点,要一起引爆嘛;join()连接这两个点;
}
if (colum[j]==0) {
colum[j]=count;//说明第i行的父节点是count;
}else {
join(colum[j],count);
}
}
}
}
input.close();
//现在判断count个炸弹哪些是一起的;判断有几个根节点;
for (int i = 1; i <= count; i++) {//从1到第count个炸弹
if (pre[i]==i) {//父节点是自己的就是根节点。
ans++;
}
}
System.out.println(ans);
}
private static void join(int i, int j) {
// TODO Auto-generated method stub
int ifather = find(i);//取出i的跟节点
int jfather = find(j);//取出j的跟节点
if (ifather!=jfather) {//这两个不是一个根节点,就连接
pre[ifather] = jfather;//让i的根节点等于j的根节点
}
}
//取出i的根节点
private static int find(int i) {
// TODO Auto-generated method stub
int root = i;
while (root!=pre[root]) {//如果root!=root自己的父节点;因为只有根节点的父节点等于自己
root = pre[root];//让root等于自己的父节点,知道找到自己的根节点为止
}
int x = i;//路径压缩
int temp = 0;
while (x!=pre[x]) {//x不为根节点的时候
temp = pre[x];//临时变量记录父节点;
pre[x] = root;//让x等于自己的根节点
x = temp;//x等于之前的父节点,继续让这一路的节点的父节点都为根节点
}
return root;//返回根节点
}
}