Kevin的算法笔记(5)搜索①
如果我们把整个草地看成一个图,那么我们要做的就是深度优先搜索每个点旁边的八个点(如果它是w),每次统计一整块草坪,同时计数器+1。
示例代码如下:
查看代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
using namespace std;
char s[100+3][100+3];
int n,m,ans;
const int tx[8]={-1,-1,-1,0,0,1,1,1};
const int ty[8]={-1,0,1,-1,1,-1,0,1};
void find(int x,int y)
{
if (x < 1 || x > n || y < 1 || y > m) return;
if (s[x][y] != 'W') return;
s[x][y]='.';
for (int i=0;i<8;i++)
find(x + tx[i], y + ty[i]);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%s",s[i]+1);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (s[i][j]=='W')
{
find(i,j);
ans++;
}
printf("%d",ans);
}
这是一道很经典的剪枝问题,如果暴力枚举,复杂度为o(2^n),一定会超时。
在BFS的基础上考虑如下方面:
①可行的长度一定是总长度S的约数
②如果已经用较大的木棍拼成一根,后续发现不可行,可直接剪枝
③如果有一根木棍比L都大,可直接剪枝
④从大木棍往小木棍搜索,更容易暴露问题
这样我们只要解决很少的几种情况即可。
参考代码如下:
查看代码
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,a[70],vis[70],ans;
bool cmp(int x,int y){
return x>y;
}
bool dfs(int len,int rest,int pos,int num){
if(!rest&&!num){
ans=len;
return true;
}
if(!rest){
rest=len;
for(int i=0;i<n;++i){
if(vis[i]) continue;
vis[i]=1;
if(dfs(len,rest-a[i],i+1,num-1))
return true;
vis[i]=0;
return false;
}
}
for(int i=pos;i<n;++i){
if(vis[i]) continue;
if(a[i]<=rest){
vis[i]=1;
if(dfs(len,rest-a[i],i+1,num-1))
return true;
vis[i]=0;
if(a[i]==rest) break;
while(a[i+1]==a[i]) ++i;
}
}
return false;
}
int main(){
while(scanf("%d",&n),n){
int sum=0,flag=0;
for(int i=0;i<n;++i){
scanf("%d",&a[i]);
sum+=a[i];
}
sort(a,a+n,cmp);
memset(vis,0,sizeof(vis));
for(int i=a[0];i<=sum/2;++i){
if(sum%i==0){
if(dfs(i,i,0,n)){
flag=1;
break;
}
}
}
if(flag)
printf("%d\n",ans);
else
printf("%d\n",sum);
}
return 0;
}
对于BFS,为了减少搜索步骤,可以使用A*算法,而对于DFS,我们可以用迭代加深算法(IDDFS)来剪枝。另外,对两者结合,迭代加深是迭代次数超过一定值就不再加深,而IDA*算法中,在某个迭代后,步数+估价函数的值超过一定大小就不再剪枝。

浙公网安备 33010602011771号