1. 程式人生 > >POJ2248-Addition Chains

POJ2248-Addition Chains

namespace 就是 -a 整數 IT tor color int 相加

滿足如下條件的序列被稱為加成序列:

X[1]=1,X[m]=n,X[1]<X[2]<......<X[m-1]<X[n]

對於每個k(2<=k<=m)都存在兩個整數i和j(1<=i,j<=k-1,i,j可以相等),使得X[k]=X[i]+X[j]。

給定一個n,找出符合上述條件的長度m最小的加成序列,多個答案輸出一個即可。n<=100

搜索,對於當前位置k,可以有任意兩個i,j相加得出,所以我一開始是兩層循環(菜死了)然後得出k再搜索k+1。

但任意兩個i,j只需要i不變,j從1到k-1枚舉得出的答案就和兩個i,j得出的一樣。只是順序不同,不影響兩者的和。

然後加入以下剪枝:

1.優化搜索順序:為了盡快得到n,盡量從大到小枚舉

2.排除等效冗余,就是加入一個數組判重

3.叠代加深,因為長度m的值不會太大(<=10),而每次搜索每個數的和,分支很多。所以可以限制搜索深度。

4.如果當前這個數連續翻倍m-k次後還是比n小,那麽就可以返回。

代碼如下:

#include <iostream>
#include <stdio.h>
#include <queue>
#include <vector>
#include <cmath>
#include <string.h>
using
namespace std; int n,arr[233],p,vis[233],ansr[233],ans; int lim; bool flag; int pow(int a,int b) { int ret=1; while(b){ if(b&1) ret=ret*a; a=a*a; b>>=1; } return ret; } void dfs(int x) { if(x==lim){ if(arr[x-1]==n){ flag
=true; for(int i=1;i<=x-1;++i) ansr[i]=arr[i]; } return ; } if(flag) return ; if(arr[x-1]*pow(2,lim-x)<n) return ; for(int i=x-1;i>=1;--i){ if(vis[arr[x-1]+arr[i]]) continue; vis[arr[x-1]+arr[i]]=1; arr[x]=arr[x-1]+arr[i]; dfs(x+1); vis[arr[x-1]+arr[i]]=0; } } int main() { while(scanf("%d",&n),n){ arr[1]=1; memset(vis,0,sizeof vis); memset(ansr,0,sizeof ansr); vis[1]=1; for(lim=2;lim<=11;lim++) { flag=false; //memset(vis,0,sizeof vis); //p=1; dfs(2); if(flag) break; } for(int i=1;i<lim-1;++i) printf("%d ",ansr[i]); printf("%d\n",ansr[lim-1]); } return 0; }

POJ2248-Addition Chains