在一个 n imes mn×m 的方格地图上,某些方格上放置着炸弹。手动引爆一个炸弹以后,炸弹会把炸弹所在的行和列上的所有炸弹引爆,被引爆的炸弹又能引爆其他炸弹,这样连锁下去。
现在为了引爆地图上的所有炸弹,需要手动引爆其中一些炸弹,为了把危险程度降到最低,请算出最少手动引爆多少个炸弹可以把地图上的所有炸弹引爆。
输入格式
第一行输两个整数 n,mn,m,用空格隔开。
接下来 nn 行,每行输入一个长度为 mm 的字符串,表示地图信息。0
表示没有炸弹,1
表示炸弹。
数据约定:
对于 60\%60% 的数据:1 le n, m le 1001≤n,m≤100;
对于 100\%100% 的数据:1 le n, m le 10001≤n,m≤1000;
数据量比较大,不建议用cin
输入。
输出格式
输出一个整数,表示最少需要手动引爆的炸弹数。
样例输入
5 5 00010 00010 01001 10001 01000
样例输出
2
算法:并查集
思路:将行和列的编号看成是单独的点,i即为i,j=j+n,然后用并查集将行和列加入集合,只有所有‘1’中行和列有一个相同(连炸特性)
的就会在一个集合中,最后并查集的集合个数就是需要的最少的投弹次数
#include <iostream> #include <cstring> #include <algorithm> using namespace std ; const int N = 2010 ; char g[N/2][N/2] ; int p[N] ; bool st[N] ; int n, m ; int find(int x){ if(x != p[x]) p[x] = find(p[x]) ; return p[x] ; } int main(){ scanf("%d%d",&n,&m) ; for(int i=0;i<n;i++){ scanf("%s",g[i]) ; } for(int i=0;i<m+n;i++){ p[i] = i ; } for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ if(g[i][j] == '1'){ int a = find(i) ; int b = find(j+n) ; if(a != b) p[a] = b ; } } } int cnt = 0 ; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ int a = find(i) ; if(!st[a] && g[i][j] == '1'){ cnt ++ ; st[a] = true ; } } } cout << cnt << endl ; return 0 ; }
...