计蒜客 A1139 引爆炸弹 DFS+剪枝

题目描述

原题链接

在一个 n × m n×m n×m 的方格地图上,某些方格上放置着炸弹。手动引爆一个炸弹以后,
炸弹会把炸弹所在的行和列上的所有炸弹引爆,被引爆的炸弹又能引爆其他炸弹,这样连锁下去。
img
现在为了引爆地图上的所有炸弹,需要手动引爆其中一些炸弹
为了把危险程度降到最低,请算出最少手动引爆多少个炸弹可以把地图上的所有炸弹引爆。

输入格式

第一行输两个整数 n , m n,m n,m用空格隔开。
接下来 n n n 行,每行输入一个长度为 m m m 的字符串,表示地图信息。0表示没有炸弹,1表示炸弹。
数据约定:
对于 60 % 60\% 60% 的数据: 1 ≤ n , m ≤ 100 1≤n,m≤100 1n,m100
对于 100 % 100\% 100% 的数据: 1 ≤ n , m ≤ 1000 1≤n,m≤1000 1n,m1000
数据量比较大,不建议用cin输入。

输出格式

输出一个整数,表示最少需要手动引爆的炸弹数。

输入样例

5 5
00010
00010
01001
10001
01000

输出样例

2

分析

炸弹会把炸弹所在的行和列上的所有炸弹引爆,被引爆的炸弹又能引爆其他炸弹,这样连锁下去
所以处于同一连通块的炸弹的引爆顺序不会对答案造成影响, 只要引爆一个炸弹, 和该炸弹处于同一连通块的炸弹都会相继被引爆
根据这一特点, 进行深搜
注意剪枝: 同一行(列)只引爆一次, 否则会超时

实现

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1009;
int n, m;
int map[N][N];
bool row[N], col[N];
int sum;
void dfs(int x, int y) // 将与(x,y)处于同一连通块的炸弹引爆
{
    if(!col[y]) // 剪枝
    {   
        col[y] = 1;
        for(int i=0; i<n; i++)
        {
            if(map[i][y] == 1)
            {
                map[i][y] = 0;
                dfs(i, y);
            }
        }
    }
    if(!row[x]) // 剪枝
    {
        row[x] = 1;
        for(int i=0; i<m; i++)
        {
            if(map[x][i] == 1)
            {
                map[x][i] = 0;
                dfs(x, i);
            }
        }
    }
    
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            scanf("%1d",&map[i][j]); 
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<m; j++)
        {
            if(map[i][j] == 1)
            {
                sum++;
                map[i][j] = 0;
                dfs(i, j);
            }
        }
    }
    cout << sum << endl;
    return 0;
}
posted @ 2021-01-24 14:43  a-shy-coder  阅读(35)  评论(0编辑  收藏  举报