计蒜客模拟题5-引爆炸弹--并查集

在一个 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;//返回根节点
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

obession

觉得有用可以打赏咖啡一杯~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值