luogu 狗哥玩木棍
阿新 • • 發佈:2019-01-10
dfs作為暴力演算法,有時候剪枝好了可以騙很多分,因此一定要多思考剪枝,註釋夠詳細了吧QAQ~
#include<iostream> #include<cmath> #include<cstdio> #include<algorithm> using namespace std; int n,m,a[21],nxt[21],lenth,sum; bool vis[21]; int flag; bool cmp(int x,int y) { return x>y; } void dfs(int k,int last,int rest) {//k為拼到第幾根,last為上次用的是第幾根木棍,rest表示該木料剩餘多少 int i; if(!rest) { if(k==4) { flag=1; return ; } for( i=1; i<=m; i++) if(!vis[i]) break; vis[i]=1; dfs(k+1,i,lenth-a[i]); vis[i]=0; if(flag) return ; } int l=last+1,r=m,mid;//二分查詢第一根比剩餘短的木棍 while(l<r) { mid=(l+r)/2; if(a[mid]<=rest) r=mid; else l=mid+1; } for( i=l; i<=m; i++) { if(!vis[i]) { vis[i]=1; dfs(k,i,rest-a[i]); vis[i]=0; if(flag) return ; } } } int main() { cin>>n; for(int i=1; i<=n; i++) { cin>>m; sum=0; for(int j=1; j<=m; j++) { cin>>a[j]; sum+=a[j]; } if(sum%4!=0) {//如果不能被4整除,邊長一定不是整數,肯定拼不出 printf("no\n"); continue; } fill(vis+1,vis+21,0);//多組資料,要初始話 sort(a+1,a+m+1,cmp);//按從大到小排列,先用大的,小的肯定比大的靈活,能不用就不用,貪心思想 for(int j=1; j<=m; j++) nxt[j]=j; for(int j=m-1; j; j--) if(a[j]==a[j+1]) nxt[j]=nxt[j+1];//因為木棍可能有相同的,所以開個nxt陣列,一根不行的話可以直接去找下一根不一樣長度的 lenth=sum/4;//正方形邊長 if(a[1]>lenth) {//如果第一根木棍就比邊長大,也拼不出 printf("no\n"); continue; } flag=0; vis[1]=1; dfs(1,1,lenth-a[1]); vis[1]=0; if(flag==1) printf("yes\n"); else printf("no\n"); } }