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