DFS之剪枝与优化
dfs和bfs都是对应一个搜索树,常用的剪枝策略:
①优化搜索顺序:大部分情况下,我们应该优先搜索分支较少的节点。
②排除等效冗余
③可行性剪枝
④最优性剪枝
⑤记忆化搜索(dp)
165. 小猫爬山
翰翰和达达饲养了 N只小猫,这天,小猫们要去爬山。
经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了(呜咕>_<)。
翰翰和达达只好花钱让它们坐索道下山。
索道上的缆车最大承重量为 W,而 N只小猫的重量分别是 C1、C2……CN。
当然,每辆缆车上的小猫的重量之和不能超过 W。
每租用一辆缆车,翰翰和达达就要付 1美元,所以他们想知道,最少需要付多少美元才能把这 N只小猫都运送下山?
输入格式
第 1行:包含两个用空格隔开的整数,N和 W。
第 2…N+1行:每行一个整数,其中第 i+1行的整数表示第 i只小猫的重量 Ci。
输出格式
输出一个整数,表示最少需要多少美元,也就是最少需要多少辆缆车。
数据范围
1≤N≤18,
1≤Ci≤W≤10^8
输入样例:
5 1996
1
2
1994
12
29
输出样例:
2
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 20;
int n,m;
int w[N];
int sum[N];
int ans=N;
void dfs(int u,int k){
//最优性剪枝
if(k>=ans) return ;
if(u==n){
ans=k;
return;
}
for(int i=0;i<k;i++){
if(sum[i]+w[u]<=m){
//可行性剪枝
sum[i]+=w[u];
dfs(u+1,k);
sum[i]-=w[u];//恢复现场
}
}
sum[k]=w[u];
dfs(u+1,k+1);
sum[k]=0;//恢复现场
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++) cin>>w[i];
//优化搜索顺序
sort(w,w+n);
reverse(w,w+n);
dfs(0,0);//从零号猫,当前车的数量是0开始搜索
cout<<ans<<endl;
return 0;
}
166. 数独
数独 是一种传统益智游戏,你需要把一个 9×9的数独补充完整,使得数独中每行、每列、每个 3×3的九宫格内数字 1∼9均恰好出现一次。
请编写一个程序填写数独。
输入格式
输入包含多组测试用例。
每个测试用例占一行,包含 81个字符,代表数独的 81个格内数据(顺序总体由上到下,同行由左到右)。
每个字符都是一个数字(1−9)或一个 .(表示尚未填充)。
您可以假设输入中的每个谜题都只有一个解决方案。
文件结尾处为包含单词 end 的单行,表示输入结束。
输出格式
每个测试用例,输出一行数据,代表填充完全后的数独。
输入样例:
4…8.5.3…7…2…6…8.4…1…6.3.7.5…2…1.4…
…52…8.4…3…9…5.1…6…2…7…3…6…1…7.4…3.
end
输出样例:
417369825632158947958724316825437169791586432346912758289643571573291684164875293
416837529982465371735129468571298643293746185864351297647913852359682714128574936
解题思路
位运算优化:行,列,九宫格,都可以用9个二进制数表示(1表示可放,0表示不能放),只有三者取&后,如果仍为1,才能放进去.
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 9,M = 1<<N;
int ones[M],map[M];
int row[N