题目大意:
给一个棋盘,问最少进行几次旋转使得中间的数字全部相等!(并且字典序最小!)
思路:
借鉴了代码仓库,感觉写的很巧妙,简单记录一下!
大致思路:
用line [][] 二维数组给棋盘进行标号!
a[] 一维数组代表当前的棋盘中棋子的标号!
center[] 一维数组代表棋盘中间棋子的标号!
rev[]数组进行反转列 ,减少了很多代码!
先判断是否合法,合法的话直接输出。NO need。。。 还有数字!
否则进行迭代加深
迭代加深中要说的有两点:
1.move函数 move(i)是进行移动!
move(rev[i])是倒回来!很巧妙!
2.if (cur + geth() > maxd)return false; 这个意思代表 需要改的 + 已经改的大于maxd的话 直接return false;进行下一次迭代加深!
注意:
当一上来就合法时别忘了输出数字,,WA了不知道几遍了~~~
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 30; int line[maxn][maxn] = { {0, 2, 6, 11, 15, 20, 22}, // A; 0 {1, 3, 8, 12, 17, 21, 23}, // B; 1 {10, 9, 8, 7, 6, 5, 4}, // C; 2 {19, 18, 17, 16, 15, 14, 13}, // D; 3 }; const int rev[maxn] = {5, 4, 7, 6, 1, 0, 3, 2}; const int center[maxn] = {6, 7, 8, 11, 12, 15, 16, 17}; int a[maxn]; char s[10000]; int dif(int k){ int sum = 0; for (int i = 0; i < 8; ++i) if (a[center[i]] != k)++sum; return sum; } int geth(){ return min(min(dif(1),dif(2)),dif(3)); } void move(int k){ int temp = a[line[k][0]]; for (int i = 0; i <= 5; ++i) a[line[k][i]] = a[line[k][i+1]]; a[line[k][6]] = temp; } bool is_ok(){ for (int i = 1; i < 8; ++i) if (a[center[i]] != a[center[0]])return false; return true; } bool dfs(int cur,int maxd){ if (is_ok()){ s[cur] = 0; printf("%s\n",s); return true; } if (cur + geth() > maxd)return false;//需要改的+已经改了的 大于maxd return false; for (int i = 0; i < 8; ++i){ s[cur] = 'A' + i; move(i); if (dfs(cur+1,maxd))return true; move(rev[i]); } return false; } int main(){ for (int i = 4; i < 8; ++i) for (int j = 0; j < 7; ++j) line[i][j] = line[rev[i]][6-j]; while(scanf("%d",&a[0]) == 1 && a[0]){ for (int i = 1; i < 24; ++i)scanf("%d",&a[i]); if (is_ok()){printf("No moves needed\n%d\n",a[16]);continue;} for (int maxd = 0;; ++maxd){ if (dfs(0,maxd))break; } printf("%d\n",a[16]); } return 0; }