两题有异曲同工之妙 觉得是DFS上的一种里程碑 在DFS递归了解得透彻的情况下 这两题的关键就在于数学思维了 刚开始写的代码总是过不了特殊数据 就开始意识到原来数学上的思维就已经不是完善的。以后要细心分析数学上的每一种可能和情况啊!
POJ2362
给出一组数据 问能否组成正方形,刚开始我数学上的逻辑就存在错误 我是先按从大到小快排从数组的第一个元素开始 去寻找他的“搭档”如果成功了就把这些元素标记为1,事实上这是错误的 因为后面的棍子可能需要和前面标记过的棍子组成边长 所以一定要全部元素都要DFS 不放过 如果后面的棍子无法组成边长了 前面的已经成功的棍子就必须拆开来寻找其他组合 再递归下去,,因为这个WA了很久 教训很深刻!!以后DFS当不行的时候一定要(回溯)!!
例如一组数据14:
20 19 17 17 16 15 12 10 10 9 5 5 4 1
如果不回溯的话《20 19 1》
《17 9 4》
然后就配不下去了,这时候就要拆开原来的组合,重新选择 最后正确组合是(20 15 5 ),(19 17 4 ),( 17 12 10 1 ), ( 16 10 9 5 )不要前面成功就定死了前面的元素。还有因为小的棍子更灵活 组成边长需要的步骤更多。所以要排序提高效率。
AC代码(没剪枝)
[code=C/C++]
[/code]#include<iostream> using namespace std; int sticks[50],b[50],len; int M,temp; int cmp(const void *a,const void *b) { return *(int*)b-*(int*)a; } bool dfs(int sum,int n) { int i; if(sum==len) { temp++; sum=0; n=0; if(temp==4) return true; } for(i=n;i<M;i++) { if(sum+sticks[i]<=len&&b[i]==0) { b[i]=1; sum+=sticks[i]; dfs(sum,i+1); if(temp==4) break; if(sum==len) temp--; sum-=sticks[i]; b[i]=0; } } if(temp==4) return true; return false; } int main() { int i,N,sum; cin>>N; while(N--) { temp=0; memset(b,0,sizeof(b)); cin>>M; sum=0; for(i=0;i<M;i++) { cin>>sticks[i]; sum+=sticks[i]; } if(sum%4!=0) cout<<"no"<<endl; else { qsort(sticks,M,sizeof(sticks[0]),cmp); len=sum/4; if(len<sticks[0]) cout<<"no"<<endl; else { if(dfs(0,0)) cout<<"yes"<<endl; else cout<<"no"<<endl; } } } return 0; }
POJ 1011
2362强化版
思维和2362一样用DFS全部搜索 不过这题对剪枝要求高!
目前我想到的剪枝
1,原始棍长要被总长度整除,否则跳过
2,因为每根棍子肯定要用到,所以如果有一根棍子找不到“搭档”组成原始长度,那么放弃这个原始长度,到下一个
3,如果搜索到某根棍子 并且这根棍子无法满足条件(递归下去所有小棍子都能组成原始长度),那么后面如果再遇到这个长度的棍子则跳过!
就这些了、
AC代码
#include<iostream> #include<cmath> using namespace std; int sticks[70],b[70]; int n,mini,num,temp,temp1; int cmp(const void *a,const void *b) { return *(int*)b-*(int*)a; } bool dfs(int len,int t) { int i; if(len==mini) { t=0; temp++; len=0; temp1=0; if(temp==num) return true; } for(i=t;i<n;i++) { if(len+sticks[i]<=mini&&b[i]==0&&temp1!=sticks[i]) { len+=sticks[i]; b[i]=1; dfs(len,i+1); if(temp==num) break; if(len==mini) temp--; len-=sticks[i]; b[i]=0; temp1=sticks[i]; } if(t==0&&temp!=4&&b[i]==0) return false; } if(temp==num) return true; else return false; } int main() { int i,sum; while(cin>>n&&n!=0) { memset(b,0,sizeof(b)); sum=0; for(i=0;i<n;i++) { cin>>sticks[i]; sum+=sticks[i]; } qsort(sticks,n,sizeof(sticks[0]),cmp); for(mini=sticks[0];;mini++) { if(sum%mini==0) { temp=0; temp1=0; num=sum/mini; if(dfs(0,0)) break; } } cout<<mini<<endl; } return 0; }
经验总结,额,因为加上剪枝的时候 有时候没控制好变量和条件,使原先可能的情况也被剪枝掉了,原因是总结确实变量掌握还有点迟钝,以后每加语句都要深深思考有什么例外情况没判断到,,否则调试要浪费很多时间了。5555555555