HDU_Steps 4.3 DFS剪枝
4.3.1 HDU1010 Tempter of the Bone
具体剪枝在这篇文章有写http://blog.csdn.net/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; }
写了个位运算搜索,果断超时啊..一看范围只有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; }
#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; }