HDU_Steps 4.3 DFS剪枝
4.3.1 HDU1010 Tempter of the Bone
具体剪枝在这篇文章有写http://blog.youkuaiyun.com/swm8023/article/details/6731109
4.3.2 HDU1016 Prime Ring Problem
直接搜就可以了,先打好40以内的素数表
4.3.3 HDU1426 Sudoku Killer
也是赤果果的搜索+回溯,对每个未填的点枚举1~9,然后判断所在列,所在行,以及所在九宫格是否有重复的没有任何剪枝170MS.
4.3.4 HDU1455 Sticks
比较经典的一道剪枝
首先要枚举长度,从最长一根的长度开始枚举,并且从大到小放置树枝
另外注意的就是会有很多长度相同的树枝,当然,对于这样的树枝,如果一根不满足条件,其它的也不会满足了
当然,这道题的剪枝还有不少,网上有大牛给出了各种剪枝,这里的两个剪枝对于这道题已经足够了~
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
int st[70],n,sum,len;
bool use[70];
bool dfs(int cnt,int rlen,int sts){//总剩余长度,该根剩下的长度,剩下的根数
if(rlen==0){
sts--;
if(sts==0)return true;
//找出当前未用的最长根作为开始
for(cnt=n;use[cnt];cnt--);
use[cnt]=true;
if(dfs(cnt-1,len-st[cnt],sts))return true;
use[cnt]=false;
sts++;
}else{
for(int i=cnt;i>=1;i--){
if(i<n&&st[i]==st[i+1]&&!use[i+1])continue;//同样长度的不行,这根同样不行
if(!use[i]&&rlen>=st[i]){
use[i]=true;
if(dfs(i-1,rlen-st[i],sts))return true;
use[i]=false;
}
}
}
return false;
}
int main(){
while(scanf("%d",&n),n){
sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&st[i]);
sum+=st[i];
}
sort(st+1,st+n+1);
for(len=st[n];len<=sum;len++){
if(sum%len!=0)continue;
memset(use,false,sizeof use);
if(dfs(n,len,sum/len)){
printf("%d\n",len);
break;
}
}
}
return 0;
}
4.3.5 HDU2510 符号三角形
写了个位运算搜索,果断超时啊..一看范围只有24,可耻的打表过了..
感觉这题可能是DP方法吧..搜索肯定是挂了..先放着,有时间再研究.
4.3.6 HDU2553 N皇后问题
看到这题就想到了67大牛的那篇文章,牛啊..短小精悍的程序
用row,ld,rd分别表示列上,左对角线上,右对角线上不能放的位置,full表示全部放满的状态..用树状数组的lowbit操作取出pos中的每一个1,也就是每一个能放的位置,然后继续搜索,左对角线和右对角线向下一行搜索时要分别右移或者左移一位
#include <cstdio>
using namespace std;
int n,res,full,ans[11];
void dfs(int row,int ld,int rd){
int pos,p;
if(row!=full){
pos=full&~(row|ld|rd);
while(pos){
p=pos&-pos;
pos-=p;
dfs(row|p,(ld|p)<<1,(rd|p)>>1);
}
}else res++;
}
int main(){
for(int i=1;i<=10;i++){
res=0;
full=(1<<i)-1;
dfs(0,0,0);
ans[i]=res;
}
while(scanf("%d",&n),n){
printf("%d\n",ans[n]);
}
return 0;
}
4.3.7 HDU3290 The magic apple tree
晕,看题目看了好久才看懂,一棵树中,第一天只有子节点开花(不记得是不是开花,反正是这个意思),数量等于节点标记,一个父节点只有当它的所有子节点都开花时才会开花,数量等于子节点的(K+1)/2
这题不能说是搜索吧,更有点像树形DP..
树是连续读入的,所有节点存在v中,num表示子节点个数,注意没有说明根节点!!!要先找到根,因为这个一直TLE,郁闷
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
int first[20001],num[20001],v[20001],vs,n,in[20001];
char c;
int getv(int p){
if(num[p]==0)return p;
nth_element(v+first[p],v+first[p]+(num[p]+1)/2-1,v+first[p]+num[p]);
return v[first[p]+(num[p]+1)/2-1];
}
void dfs(int p){
for(int i=0;i<num[p];i++){
int t=v[first[p]+i];
if(num[t]!=0)dfs(t);
v[first[p]+i]= getv(t);//跟新当前节点值
}
}
inline void scan(int &x){
while(c=getchar(),c<'0'||c>'9');
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0';
}
int main(){
while(scanf("%d",&n)!=EOF){
first[1]=1;
vs=1;
for(int i=1;i<=n;i++)in[i]=0;
for(int i=1;i<=n;i++){
scan(num[i]);//child个数,也是child所占连续空间
for(int j=0;j<num[i];j++){
scan(v[vs]);
in[v[vs]]++;
vs++;
}
first[i+1]=first[i]+num[i];//标记下一个节点child的存储开始位置
}
first[0]=0,num[0]=1;
for(int i=1;i<=n;i++){if(in[i]==0){v[0]=i;break;}}
dfs(0);
printf("%d\n",v[0]);
}
return 0;
}
4.3.8 HDU2616 Kill the monster
简单的深搜+回溯
#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;
int n,m,bella[12],bellm[12],a[12],use[12],res;
void dfs(int p){
if(p==n+1){
int nowm=m;
for(int i=1;i<=n;i++){
if(nowm<=bellm[a[i]])nowm-=2*bella[a[i]];
else nowm-=bella[a[i]];
if(nowm<=0){
res=min(res,i);
}
}
}
for(int i=1;i<=n;i++){
if(!use[i]){
use[i]=1;
a[p]=i;
dfs(p+1);
use[i]=0;
}
}
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=1;i<=n;i++)scanf("%d%d",&bella[i],&bellm[i]);
memset(use,0,sizeof use);
res=20;
dfs(1);
if(res!=20)printf("%d\n",res);
else printf("-1\n");
}
return 0;
}