[cpp] view plaincopyprint?
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #include <iostream>
- #include <queue>
- #include <map>
-
- using namespace std;
-
- #define LEFT_CLOCKWISE 1 // 左侧顺时针。
- #define RIGHT_CLOCKWISE 2 // 右侧顺时针。
- #define LEFT_COUNTERCLOCKWISE 3 // 左侧逆时针。
- #define RIGHT_COUNTERCLOCKWISE 4 // 右侧逆时针。
-
- #define NWHEEL 24 // 滑块总数目。
- #define HALF_WHEEL 9 // 左侧滑块的数目。
- #define MIDDLE_WHEEL 3 // 中间滑块的数目。
- #define BACKWARD_DEPTH 8 // 逆向搜索深度。
-
-
-
- string target = "034305650078709T90121";
-
-
- map < string, string > cache;
-
-
- int reverse[4] = { 3, 4, 1, 2 };
-
-
- struct node
- {
- string config;
- string sequences;
- };
-
-
- void rotate(string &config, int direction)
- {
-
- string middle = config.substr(HALF_WHEEL * 2);
-
- switch (direction)
- {
-
- case LEFT_CLOCKWISE:
-
- config[HALF_WHEEL * 2] = config[HALF_WHEEL - 2];
- config[HALF_WHEEL * 2 + 1] = config[HALF_WHEEL - 1];
- config[HALF_WHEEL * 2 + 2] = middle[0];
-
- for (int i = HALF_WHEEL - 1; i >= 2; i--)
- config[i] = config[i - 2];
- config[1] = middle[2];
- config[0] = middle[1];
-
- break;
-
-
- case RIGHT_CLOCKWISE:
-
- config[HALF_WHEEL * 2] = middle[2];
- config[HALF_WHEEL * 2 + 1] = config[HALF_WHEEL];
- config[HALF_WHEEL * 2 + 2] = config[HALF_WHEEL + 1];
-
- for (int i = HALF_WHEEL; i <= (HALF_WHEEL * 2 - 3); i++)
- config[i] = config[i + 2];
- config[HALF_WHEEL * 2 - 2] = middle[0];
- config[HALF_WHEEL * 2 - 1] = middle[1];
-
- break;
-
-
- case LEFT_COUNTERCLOCKWISE:
-
- config[HALF_WHEEL * 2] = middle[2];
- config[HALF_WHEEL * 2 + 1] = config[0];
- config[HALF_WHEEL * 2 + 2] = config[1];
-
- for (int i = 0; i <= HALF_WHEEL - 3; i++)
- config[i] = config[i + 2];
- config[HALF_WHEEL - 2] = middle[0];
- config[HALF_WHEEL - 1] = middle[1];
-
- break;
-
-
- case RIGHT_COUNTERCLOCKWISE:
-
- config[HALF_WHEEL * 2] = config[HALF_WHEEL * 2 - 2];
- config[HALF_WHEEL * 2 + 1] = config[HALF_WHEEL * 2 - 1];
- config[HALF_WHEEL * 2 + 2] = middle[0];
-
- for (int i = 2 * HALF_WHEEL - 1; i >= HALF_WHEEL + 2; i--)
- config[i] = config[i - 2];
- config[HALF_WHEEL + 1] = middle[2];
- config[HALF_WHEEL] = middle[1];
-
- break;
- }
- }
-
-
-
- void backward_search(string config)
- {
- queue <node> open;
-
- node tmp;
- tmp.config = config;
- tmp.sequences = "";
-
- open.push(tmp);
-
- while (!open.empty())
- {
- node copy = open.front();
- open.pop();
-
-
- if (copy.sequences.length() >= BACKWARD_DEPTH)
- continue;
-
- for (int i = LEFT_CLOCKWISE; i <= RIGHT_COUNTERCLOCKWISE; i++)
- {
-
-
- if (copy.sequences.length() > 0)
- {
-
- int last_rotate = reverse[copy.sequences[0] - '0' - 1];
- if (last_rotate != i && ((last_rotate + i) == 4 ||
- (last_rotate + i) == 6))
- continue;
- }
-
- string t = copy.config;
- rotate(t, i);
-
- if (cache.find(t) == cache.end())
- {
- node successor;
- successor.config = t;
-
- successor.sequences = (char)('0' + reverse[i - 1]) + copy.sequences;
- open.push(successor);
-
- cache.insert(make_pair<string, string>(t, successor.sequences));
- }
- }
- }
- }
-
-
- bool forward_search(string config)
- {
- queue <node> open;
-
- node tmp;
- tmp.config = config;
- tmp.sequences = "";
-
- open.push(tmp);
-
- while (!open.empty())
- {
- node copy = open.front();
- open.pop();
-
-
- if (cache.find(copy.config) != cache.end())
- {
- cout << copy.sequences;
- map <string, string>::iterator it = cache.find(copy.config);
- cout << (*it).second << endl;
-
- return true;
- }
-
-
- if (copy.sequences.length() >= (BACKWARD_DEPTH + 1))
- continue;
-
- for (int i = LEFT_CLOCKWISE; i <= RIGHT_COUNTERCLOCKWISE; i++)
- {
-
- if (copy.sequences.length() > 0)
- {
- int size = copy.sequences.length();
- int last_rotate = copy.sequences[size - 1] - '0';
- if (last_rotate != i && ((last_rotate + i) == 4 ||
- (last_rotate + i) == 6))
- continue;
- }
-
- string t = copy.config;
- rotate(t, i);
-
- node successor;
- successor.config = t;
- successor.sequences = copy.sequences + (char)('0' + i);
-
- open.push(successor);
- }
- }
-
- return false;
- }
-
-
- bool solved(string config)
- {
- for (int i = 0; i < target.length(); i++)
- if (config[i] != target[i])
- return false;
-
- return true;
- }
-
- int main(int ac, char *av[])
- {
- string config;
- int c;
- int cases;
-
-
- backward_search(target);
-
- cin >> cases;
- while (cases--)
- {
-
- config.clear();
- for (int i = 0; i < NWHEEL; i++)
- {
- cin >> c;
- if (c == 10)
- config.append(1, 'T');
- else
- config.append(1, c + '0');
- }
-
-
- config = config.substr(0, HALF_WHEEL) +
- config.substr(HALF_WHEEL + MIDDLE_WHEEL, HALF_WHEEL) +
- config.substr(2 * HALF_WHEEL + MIDDLE_WHEEL);
-
-
- if (solved(config))
- {
- cout << "PUZZLE ALREADY SOLVED" << endl;
- continue;
- }
-
-
- if (!forward_search(config))
- cout << "NO SOLUTION WAS FOUND IN 16 STEPS" << endl;
- }
-
- return 0;
- }
// Colour Hash (色彩缤纷游戏)// PC/UVa IDs: 110807/704, Popularity: B, Success rate: average Level: 3// Verdict: Accepted// Submission Date: 2011-08-28// UVa Run Time: 0.048s//// 版权所有(C)2011,邱秋。metaphysis # yeah dot net//// 若从给定状态进行单向搜索,由于状态较多,容易 TLE,故采用双向搜索的办法,逆向搜索:从目标状态// 搜索 8 步,把所有得到的结果记录在集合 A 中;正向搜索:从给定状态搜索 9 步,若在搜索过程中生成// 的某个状态在集合 A 中,则表明在 16 步内能找到解,否则无法找到解。//// 这里较为关键的是如何表示游戏的当前状态,以避免在集合 A 中添加重复的状态,可以使用字符串来表示// 当前的滑块状态。集合 A 可以使用 map 来判断是否已经有重复的状态产生。#include <iostream>#include <queue>#include <map>using namespace std;#define LEFT_CLOCKWISE 1// 左侧顺时针。#define RIGHT_CLOCKWISE 2// 右侧顺时针。#define LEFT_COUNTERCLOCKWISE 3// 左侧逆时针。#define RIGHT_COUNTERCLOCKWISE 4// 右侧逆时针。#define NWHEEL 24// 滑块总数目。#define HALF_WHEEL 9// 左侧滑块的数目。#define MIDDLE_WHEEL 3// 中间滑块的数目。#define BACKWARD_DEPTH 8// 逆向搜索深度。// 目标状态。存储方式为左侧滑块-右侧滑块-中间滑块,因为编号为 10 的滑块占两个字符,故用 10 的英// 文(ten)首字母 T 来表示。string target = "034305650078709T90121";// 逆向搜索的缓存,使用字符串来表示状态和旋转序列。map < string, string > cache;// 旋转操作的逆。1 的逆为 3,2 的逆为 4,依此类推。int reverse[4] = { 3, 4, 1, 2 };// 表示滑块当前状态的结构。struct node{string config;// 滑块状态。string sequences;// 到达此位置的旋转序列。};// 按指定的方向旋转滑块。void rotate(string &config, int direction){// 获取中间滑块部分。string middle = config.substr(HALF_WHEEL * 2);switch (direction){// 左侧滑块顺时针旋转。case LEFT_CLOCKWISE:config[HALF_WHEEL * 2] = config[HALF_WHEEL - 2];config[HALF_WHEEL * 2 + 1] = config[HALF_WHEEL - 1];config[HALF_WHEEL * 2 + 2] = middle[0];for (int i = HALF_WHEEL - 1; i >= 2; i--)config[i] = config[i - 2];config[1] = middle[2];config[0] = middle[1];break;// 右侧滑块顺时针旋转。case RIGHT_CLOCKWISE:config[HALF_WHEEL * 2] = middle[2];config[HALF_WHEEL * 2 + 1] = config[HALF_WHEEL];config[HALF_WHEEL * 2 + 2] = config[HALF_WHEEL + 1];for (int i = HALF_WHEEL; i <= (HALF_WHEEL * 2 - 3); i++)config[i] = config[i + 2];config[HALF_WHEEL * 2 - 2] = middle[0];config[HALF_WHEEL * 2 - 1] = middle[1];break;// 左侧滑块逆时针旋转。case LEFT_COUNTERCLOCKWISE:config[HALF_WHEEL * 2] = middle[2];config[HALF_WHEEL * 2 + 1] = config[0];config[HALF_WHEEL * 2 + 2] = config[1];for (int i = 0; i <= HALF_WHEEL - 3; i++)config[i] = config[i + 2];config[HALF_WHEEL - 2] = middle[0];config[HALF_WHEEL - 1] = middle[1];break;// 右侧滑块逆时针旋转。case RIGHT_COUNTERCLOCKWISE:config[HALF_WHEEL * 2] = config[HALF_WHEEL * 2 - 2];config[HALF_WHEEL * 2 + 1] = config[HALF_WHEEL * 2 - 1];config[HALF_WHEEL * 2 + 2] = middle[0];for (int i = 2 * HALF_WHEEL - 1; i >= HALF_WHEEL + 2; i--)config[i] = config[i - 2];config[HALF_WHEEL + 1] = middle[2];config[HALF_WHEEL] = middle[1];break;}}// 从目标状态生成 8 步内所有可能产生的状态,使用宽度优先搜索的方法,用 map 存储生成的状态和相应// 的旋转序列。void backward_search(string config){queue <node> open;node tmp;tmp.config = config;tmp.sequences = "";open.push(tmp);while (!open.empty()){node copy = open.front();open.pop();// 当扩展的深度达到 8 层后停止在此状态上继续扩展。if (copy.sequences.length() >= BACKWARD_DEPTH)continue;for (int i = LEFT_CLOCKWISE; i <= RIGHT_COUNTERCLOCKWISE; i++){// 跳过无效的移动,例如前一步采用了左侧顺时针旋转,则当前若使用// 左侧逆时针旋转会回到上一步的状态。if (copy.sequences.length() > 0){// 注意使用的是旋转操作的逆,故需还原后判断。int last_rotate = reverse[copy.sequences[0] - '0' - 1];if (last_rotate != i && ((last_rotate + i) == 4 || (last_rotate + i) == 6))continue;}string t = copy.config;rotate(t, i);if (cache.find(t) == cache.end()){node successor;successor.config = t;// 记录逆向搜索的旋转序列时,使用当前旋转的逆。successor.sequences = (char)('0' + reverse[i - 1]) + copy.sequences;open.push(successor);cache.insert(make_pair<string, string>(t, successor.sequences));}}}}// 进行正向搜索,采用宽度优先搜索模式。bool forward_search(string config){queue <node> open;node tmp;tmp.config = config;tmp.sequences = "";open.push(tmp);while (!open.empty()){node copy = open.front();open.pop();// 已经找到在缓存中的状态,输出旋转序列。if (cache.find(copy.config) != cache.end()){cout << copy.sequences;map <string, string>::iterator it = cache.find(copy.config);cout << (*it).second << endl;return true;}// 搜索深度为 9。if (copy.sequences.length() >= (BACKWARD_DEPTH + 1))continue;for (int i = LEFT_CLOCKWISE; i <= RIGHT_COUNTERCLOCKWISE; i++){// 若前后两步构成互补状态则跳过。if (copy.sequences.length() > 0){int size = copy.sequences.length();int last_rotate = copy.sequences[size - 1] - '0';if (last_rotate != i && ((last_rotate + i) == 4 || (last_rotate + i) == 6))continue;}string t = copy.config;rotate(t, i);node successor;successor.config = t;successor.sequences = copy.sequences + (char)('0' + i);open.push(successor);}}return false;}// 和目标状态比较,确定是否为已解决状态。bool solved(string config){for (int i = 0; i < target.length(); i++)if (config[i] != target[i])return false;return true;}int main(int ac, char *av[]){string config;int c;int cases;// 先生成逆向搜索的结果以备查。backward_search(target);cin >> cases;while (cases--){// 读入初始状态。config.clear();for (int i = 0; i < NWHEEL; i++){cin >> c;if (c == 10)config.append(1, 'T');elseconfig.append(1, c + '0');}// 调整表示形式。config = config.substr(0, HALF_WHEEL) +config.substr(HALF_WHEEL + MIDDLE_WHEEL, HALF_WHEEL) +config.substr(2 * HALF_WHEEL + MIDDLE_WHEEL);// 先判断是否已经为解决状态。if (solved(config)){cout << "PUZZLE ALREADY SOLVED" << endl;continue;}// 进行正向搜索查找。if (!forward_search(config))cout << "NO SOLUTION WAS FOUND IN 16 STEPS" << endl;}return 0;}