题意给你一个n*m的矩阵,矩阵有0点,有1点,你放一个雷,就会让和雷所在的同一行和同一列的所有1变成0.n和m小于,问最少放几个雷?
思路我一开始想了个二分图,想行是一个集合,列是一个集合,然后每一个点去建一条边,想了想完美匹配的东西,但是发现。。。好像不行。。。然后这是个搜索。因为你看他不到25位,就可以状压成一个int值。然后不断的搞来搞去。
1,先把矩阵的每一行处理成一个int值。
2,然后搜索,搜索的方向就是这一行放雷还是不放雷,如果放雷的话,看看还有那一些列需要炸。(这是一个状态)先处理了每一行,然后上一个状态和当前行没放雷的状态|(或)操作一下就可以了。(PS:如果你放雷的话,这一行就没有1,你就可以直接用上一个状态,不用或了)
3,当你放到最后一行的时候,你需要知道最终状态有多少个雷,这样一般来讲是要除2然后%2,但是这样会t,所以先给他预处理一下,怎么预处理呢?就是用lowbit去,(如果不会可以看一看树状数组)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
typedef long long LL;
int n , m;
int f[(int)4e7] , _min, P[40];
char s[50][50];
void dfs(int d , int a , int b)//d 行, 放了a个雷 , 列的状态
{
if(d > n){
b = f[b];
_min = min(_min , a + (max(a , b) - a));
}
else{
dfs(d + 1 , a + 1 , b);
dfs(d + 1 , a , b | P[d]);
}
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
for(int i = 1 ; i <= (1 << 25) ; i++) f[i] = f[i ^ (i & (-i))] + 1;//这个是lowbit
while(~scanf("%d %d",&n , &m)){
_min = n * m;
for(int i = 1 ; i <= n ; i++){
for(int j = 1 ; j <= m ; j++) scanf(" %c",&s[i][j]);
}
for(int i = 1 ; i <= n ; i++){
int sum = 0 , ans = 1;
for(int j = m ; j >= 1 ; j--){
if(s[i][j] == '*') sum += ans;
ans *= 2;
}
P[i] = sum;
}
dfs(1 , 0 , 0);
printf("%d\n",_min);
}
return 0;
}
本文介绍了一种通过状态压缩和深度优先搜索解决矩阵雷击问题的方法。该问题要求在矩阵中放置最少数量的雷,使得所有标记为1的单元格变为0。文章详细解释了如何将矩阵行转换为整数表示,并通过搜索确定最佳解决方案。
5276

被折叠的 条评论
为什么被折叠?



