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;}
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;}