Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
Re:回溯(剪枝)法In Reply To:回溯(剪枝)法 Posted by:18860012175 at 2020-05-14 11:32:48 > /** > * POJ1753,Accepted > * 棋盘上每一个棋子都有翻转和不翻转两种选择 > * 总共16个棋子,就是2^16种可能 > * 问题的解是这所有可能的一个子集 > * 在此利用回溯法遍历子集树 > * 剪枝函数设定为:当前已经翻转的次数如果大于已经得到的最优次数则不再往下 > * 由于问题是求解最少的翻转次数,为了提高效率,回溯函数中优先搜索不翻转的情况 > * 这样的话搜索过程中翻转的次数就是递增的,一旦得到结果,剩余的翻转次数更多的情况会被剪枝 > * 每得到一个子集,检查棋盘状态和翻转次数是否更少(递归出口) > */ > #include <stdio.h> > > int Checkerboard[16];//4x4棋盘,0代表白,1代表黑 > int Count = 20;//记录最优翻转次数,由于最多翻转16次,初始化大于16的数 > int times;//自动初始化0,记录当前已经翻转的次数,用于剪枝函数,若times>Count则没必要往下 > bool Check(){//检查是否全部同色 > for(int i=0;i<16;++i){ > if(Checkerboard[0]!=Checkerboard[i]) > return false; > } > return true; > } > void Flip(int target){//翻转target及其上下左右棋子 > int r = target/4;//用于辨别边界棋子 > int c = target%4;//同上 > Checkerboard[target] = !Checkerboard[target]; > if(r>0) Checkerboard[target-4] = !Checkerboard[target-4]; > if(r<3) Checkerboard[target+4] = !Checkerboard[target+4]; > if(c>0) Checkerboard[target-1] = !Checkerboard[target-1]; > if(c<3) Checkerboard[target+1] = !Checkerboard[target+1]; > } > void Backtrack(int i){ > if(i>=16){//得到一个子集 > if(Check()&×<Count) Count = times; > } > else{ > Backtrack(i+1);//优先不翻转,提高效率 > times++;//翻转后的总翻转次数 > int flag = 0;//标记是否翻转 > if(times<Count) { > Flip(i);//翻转 > flag = 1; > Backtrack(i+1); > } > if(flag) Flip(i);//回溯,恢复上一次状态 > times--; > } > } > int main(){ > char ch; > for(int i=0;i<16;++i){ > ch = getchar(); > if(ch=='\n'){ > --i; > continue; > } > Checkerboard[i] = (119-ch)/21;//哈希函数,直接把w映射到0,b映射到1 > } > Backtrack(0); > if(Count==20) printf("Impossible\n"); > else printf("%d\n",Count); > return 0; > } Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator