POJ1011 dfs剪枝
阿新 • • 發佈:2018-12-07
B站上老師已經講的很清楚了,我掛個程式碼;
B站:https://www.bilibili.com/video/av10046345/?p=18
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const double epos=1e-8; const int maxn=100; int a[maxn]; int n; int flag[maxn]; int L; int lastst; int dfs(int r,int m){ if(r==0&&m==0) return 1; if(m==0) m=L; /* 根子拼接中若出現前面的這一小部分比後面這一小部分長,則說明對調後, 按照順序也是可以拼接的,於是這個st可以保證拼接棍子中,小棍子都是有序的; */ int st=(m==L?0:lastst+1); for(int i=st;i<n;i++){ if(flag[i]==1||a[i]>m) continue; //上一根拼接不成功,則不必再試和它長度相同的根子; if(i>0&&flag[i-1]==0&&a[i]==a[i-1]) continue; flag[i]=1; lastst=i; if(dfs(r-1,m-a[i])) return 1; //情況不成立,回溯; flag[i]=0; //後面拼接不成功,回溯到了最開始,而替換第一根木棍是沒有意義的,因為替換最長的這一根後,他仍會出現在後續棍子中; if(m==L) return 0; //這個剪枝我還不理解...太菜了QAQ; if(a[i]==m) return 0; } return 0; } bool cmp(const int& x,const int& y){ return x>y; } int main(){ while(scanf("%d",&n)!=EOF&&n){ int sum=0; for(int i=0;i<n;i++){ scanf("%d",&a[i]); sum+=a[i]; } int maxx=sum; sort(a,a+n,cmp); int hhh=0; for(L=a[0];L<=sum/2;L++){ if(sum%L) continue; memset(flag,0,sizeof(flag)); lastst=0; if(dfs(n,L)){ hhh=1; break; } } if(hhh) printf("%d\n",L); else printf("%d\n",maxx); } return 0; }
最後一個剪枝,先抄大佬一段話://剪枝3:假設len[i]為最後一根木棒,被更小木棒替換後最終能夠成功,那麼3必然出現在後面的某個棍子k裡。 //將棍子k中的len[i]和棍子i中用來替換3的幾根木棒對調,結果當然一樣是成功的。這就和i原來的拼法會導致不成功矛盾。