剪枝:
1.当前用的杀虫剂的个数超过了当前最优值,剪掉
2.当前的点上有虫子,必须要放杀虫剂,因为杀虫剂的范围是lawn[i][j],law[i][j+1],law[i+1][j],law[i+1][j+1],如果不放的话,后面就没有机会杀掉这个位置上的虫子了,想想就明白了
3.如果当前位置放了杀虫剂,那么可以直接跳到ci,cj+2位置,因为杀虫剂的范围内已经没有虫子了,没有必要.
4.如果下一行完全没有虫子,那么可以跳到ci+2,0的位置再开始,理由同上
#include <iostream>
#include <cstdio>
#include <memory.h>
using namespace std;
const int maxn=8;
char lawn[maxn][maxn];
int n,m,ans;
int di[]={0,0,1,1},dj[]={0,1,0,1};
void dfs(int ci,int cj,int left,int cnt){
if(left<=0){
ans=min(ans,cnt);
return;
}else if(cnt>=ans||ci>=n)return;
int kill=0;
bool put[4]={0};
for (int i=0;i<4;++i){
int ni=ci+di[i],nj=cj+dj[i];
if(ni>=0&&ni<n&&nj>=0&&nj<m&&lawn[ni][nj]=='o'){
put[i]=1;
kill++;
lawn[ni][nj]='.';
}
}
if(kill){
if(cj+2<m)dfs(ci,cj+2,left-kill,cnt+1);
else{
if(ci+1<n){//边界
int i;
for (i=0;i<m;++i){//判断下一行是否都是空的
if(lawn[ci+1][i]=='o')break;
}
if(i==m)dfs(ci+2,0,left-kill,cnt+1);
else dfs(ci+1,0,left-kill,cnt+1);
}else{
dfs(ci+1,0,left-kill,cnt+1);
}
}
//还原现场
for (int i=0;i<4;++i){
if(put[i]){
int ni=ci+di[i],nj=cj+dj[i];
lawn[ni][nj]='o';
}
}
}
if(lawn[ci][cj]=='.'){//不放杀虫剂的前提是这个点上没有虫子
if(cj+1<m)dfs(ci,cj+1,left,cnt);
else{
if(ci+1<n){
int i;
for (i=0;i<m;++i){//判断下一行是否都是空的
if(lawn[ci+1][i]=='o')break;
}
if(i==m)dfs(ci+2,0,left,cnt);
else dfs(ci+1,0,left,cnt);
}else{
dfs(ci+1,0,left,cnt);
}
}
}
}
int main(){
while (scanf("%d%d",&n,&m)){
if(!n&&!m)break;
int cnt=0;
ans=16;
for (int i=0;i<n;++i){
for (int j=0;j<m;++j){
cin>>lawn[i][j];
if(lawn[i][j]=='o')cnt++;
}
}
dfs(0,0,cnt,0);
printf("%d\n",ans);
}
return 0;
}