题意给你一个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;
}