• UVA-1343 旋转游戏 题解答案代码 算法竞赛入门经典第二版


    GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版

    题目其实不难,但是耗费了我较多时间。

    这种题关键就是在于找到约束条件,我在DFS的基础上,试了很多种策略:

    1. 对3种数字,每种数字递归遍历一次,这样每次只需要关注一种数字的变化,情况更少。

    2. 使用一个long long类型的数字作为map的key,key表示这种数字在图形中分别的位置,value表示在第几步访问过。如果重复访问且步数更长,则不继续递归。

    3. 使用剪枝策略,认为不符合情况结点不继续遍历。(但是我想的剪枝方法不合理,使用了之后是错误的,在最后有给出)

    4. 迭代加深搜索,一层一层更深的查找。适用于本题次数最少的要求。

    5. 乐观估价函数:在中心每个点的值不对的情况下,每个点都至少需要一次移动才能正确。因此估价函数为 不正确的点数+现有的步数 <= 要求的最大步数。

    上述的方法是结合使用的,一开始没想到估价函数,一直在剪枝策略中纠结,然后一直超时。最后换成了估价函数,时间瞬间缩短了。

    虽然移动的可能性是无限的,但是最多的移动次数也就是十几次。

    AC代码

    1. #include
    2. #include
    3. #include
    4. #define MAXLEN 15
    5. using namespace std;
    6. int arr[24];
    7. int arrCon[4][7];
    8. // 是否访问过的记录
    9. map<long long, int> mp;
    10. // 记录三种数字完成时的移动情况
    11. char moves[3][MAXLEN + 5];
    12. // 移动数组的长度
    13. int moveCount[3];
    14. // 每个移动数组代表的移动类型(可能并不是下表所指示的那个)
    15. int moveType[3];
    16. // 从输入数据转换为四数组模式
    17. void convertArr() {
    18. int i;
    19. arrCon[0][0] = arr[0]; arrCon[1][0] = arr[1];
    20. arrCon[0][1] = arr[2]; arrCon[1][1] = arr[3];
    21. for(i = 0; i < 7; ++i) arrCon[2][i] = arr[4 + i];
    22. arrCon[0][2] = arr[6]; arrCon[1][2] = arr[8];
    23. arrCon[0][3] = arr[11]; arrCon[1][3] = arr[12];
    24. for(i = 0; i < 7; ++i) arrCon[3][i] = arr[13 + i];
    25. arrCon[0][4] = arr[15]; arrCon[1][4] = arr[17];
    26. arrCon[0][5] = arr[20]; arrCon[1][5] = arr[21];
    27. arrCon[0][6] = arr[22]; arrCon[1][6] = arr[23];
    28. }
    29. // 对一个数组移动位置 type->0 往大移动 type->1 往小移动
    30. void moveArr(int *arrSrc, int type) {
    31. int t, i;
    32. if(type == 0) {
    33. t = arrSrc[6];
    34. for(i = 6; i > 0; --i) arrSrc[i] = arrSrc[i-1];
    35. arrSrc[0] = t;
    36. } else {
    37. t = arrSrc[0];
    38. for(i = 0; i < 6; ++i) arrSrc[i] = arrSrc[i+1];
    39. arrSrc[6] = t;
    40. }
    41. }
    42. // 按照某个方向移动 flag->1 移动 flag->0 恢复移动
    43. void moveStep(int num, bool flag) {
    44. bool type;
    45. switch(num) {
    46. case 0:
    47. case 5:
    48. type = num < 4 ? 1 : 0;
    49. type = flag ? type : !type;
    50. moveArr(arrCon[0], type);
    51. arrCon[2][2] = arrCon[0][2];
    52. arrCon[3][2] = arrCon[0][4];
    53. break;
    54. case 1:
    55. case 4:
    56. type = num < 4 ? 1 : 0;
    57. type = flag ? type : !type;
    58. moveArr(arrCon[1], type);
    59. arrCon[2][4] = arrCon[1][2];
    60. arrCon[3][4] = arrCon[1][4];
    61. break;
    62. case 2:
    63. case 7:
    64. type = num < 4 ? 0 : 1;
    65. type = flag ? type : !type;
    66. moveArr(arrCon[2], type);
    67. arrCon[0][2] = arrCon[2][2];
    68. arrCon[1][2] = arrCon[2][4];
    69. break;
    70. case 3:
    71. case 6:
    72. type = num < 4 ? 0 : 1;
    73. type = flag ? type : !type;
    74. moveArr(arrCon[3], type);
    75. arrCon[0][4] = arrCon[3][2];
    76. arrCon[1][4] = arrCon[3][4];
    77. break;
    78. }
    79. }
    80. // 是否成功 返回成功的字符 否则0
    81. int isArrive() {
    82. int num = arrCon[0][2];
    83. if(arrCon[0][3] != num || arrCon[0][4] != num || arrCon[1][2] != num || arrCon[1][3] != num)
    84. return 0;
    85. if(arrCon[1][4] != num || arrCon[2][3] != num || arrCon[3][3] != num)
    86. return 0;
    87. return num;
    88. }
    89. // 根据数字在四数组中的位置,转换为0-27的数字数组
    90. long long getArrPos(int num) {
    91. int i, j;
    92. long long sum = 0;
    93. for(i = 0; i < 4; ++i) {
    94. for(j = 0; j < 7; ++j) {
    95. if(arrCon[i][j] == num) {
    96. if(i < 2) {
    97. sum = (sum << 5) + i * 7 + j;
    98. } else {
    99. if(j == 2 || j == 4) continue;
    100. sum = (sum << 5) + i * 7 + j;
    101. }
    102. }
    103. }
    104. }
    105. return sum;
    106. }
    107. // 剪枝
    108. bool shouldMove(int num, int step) {
    109. switch(step) {
    110. case 0:
    111. if(arrCon[0][5] == num || arrCon[0][6] == num || arrCon[0][4] == num) return true;
    112. break;
    113. case 1:
    114. if(arrCon[1][5] == num || arrCon[1][6] == num || arrCon[1][4] == num) return true;
    115. break;
    116. case 2:
    117. if(arrCon[2][0] == num || arrCon[2][1] == num || arrCon[2][2] == num) return true;
    118. break;
    119. case 3:
    120. if(arrCon[3][0] == num || arrCon[3][1] == num || arrCon[3][2] == num) return true;
    121. break;
    122. case 4:
    123. if(arrCon[1][0] == num || arrCon[1][1] == num || arrCon[1][2] == num) return true;
    124. break;
    125. case 5:
    126. if(arrCon[0][0] == num || arrCon[0][1] == num || arrCon[0][2] == num) return true;
    127. break;
    128. case 6:
    129. if(arrCon[3][5] == num || arrCon[3][6] == num || arrCon[3][4] == num) return true;
    130. break;
    131. case 7:
    132. if(arrCon[2][5] == num || arrCon[2][6] == num || arrCon[2][4] == num) return true;
    133. break;
    134. }
    135. return false;
    136. }
    137. // 估价函数 true代表有机会 false代表没机会
    138. bool hvalue(int num, int stepCount, int k) {
    139. int i, j, value = 0;
    140. for(i = 0; i < 4; ++i) {
    141. if(arrCon[i][3] != num) value += 1;
    142. }
    143. if(arrCon[0][2] != num) value += 1;
    144. if(arrCon[0][4] != num) value += 1;
    145. if(arrCon[1][2] != num) value += 1;
    146. if(arrCon[1][4] != num) value += 1;
    147. return stepCount + value < k;
    148. }
    149. //递归寻找
    150. int getValue(int num, int stepCount, int k) {
    151. int resArr = isArrive();
    152. if(resArr) {
    153. moveType[num - 1] = resArr;
    154. return stepCount;
    155. }
    156. if(stepCount >= k) return 0;
    157. if(!hvalue(num, stepCount, k)) return 0;
    158. int i, count, res;
    159. long long sum;
    160. // printf(" ------ %d\n", stepCount);
    161. for(i = 0; i < 8; ++i) {
    162. // if(!shouldMove(num, i)) continue;
    163. // 移动
    164. moveStep(i, true);
    165. // printf(" ----------- %d\n", isFind(num));
    166. sum = getArrPos(num);
    167. count = mp[sum];
    168. if(!count || count > stepCount) {
    169. mp[sum] = stepCount;
    170. // 记录步骤
    171. moves[num-1][stepCount] = i;
    172. // 访问子节点
    173. res = getValue(num, stepCount+1, k);
    174. if(res) {
    175. // 复位
    176. moveStep(i, false);
    177. return res;
    178. }
    179. }
    180. // 复位
    181. moveStep(i, false);
    182. }
    183. return 0;
    184. }
    185. int getRes(int k) {
    186. int i, j, mini, minV;
    187. for(i = 0; i < 3; ++i) {
    188. mp.clear();
    189. long long sum = getArrPos(i+1);
    190. mp[sum] = 0;
    191. moveCount[i] = getValue(i+1, 0, k);
    192. if(moveCount[i] > 0) k = moveCount[i];
    193. // printf("-- %d %d %d \n", k, i, moveCount[i-1]);
    194. // moves[i-1][moveCount[i-1]] = 0;
    195. }
    196. minV = MAXLEN + 10;
    197. mini = -1;
    198. for(i = 0; i < 3; ++i) {
    199. if(moveCount[i] == 0) continue;
    200. // printf( "[]%d\n", moveCount[i]);
    201. if(minV > moveCount[i]) {
    202. minV = moveCount[i];
    203. mini = i;
    204. } else if(minV == moveCount[i]) {
    205. if(strcmp(moves[mini], moves[i]) > 0) {
    206. minV = moveCount[i];
    207. mini = i;
    208. }
    209. }
    210. }
    211. return mini;
    212. }
    213. int main() {
    214. int i, j, k;
    215. while(1) {
    216. if(scanf("%d", &arr[0]) != 1 || arr[0] == 0) break;
    217. for(i = 1; i < 24; ++i) {
    218. scanf("%d", &arr[i]);
    219. }
    220. convertArr();
    221. int resType = isArrive();
    222. if(resType) {
    223. printf("No moves needed\n");
    224. printf("%d\n", resType);
    225. continue;
    226. }
    227. for(i = 1; i < MAXLEN; ++i) {
    228. k = getRes(i);
    229. if(k >= 0) break;
    230. }
    231. if(moveCount[k] == 0) {
    232. printf("No moves needed\n");
    233. } else {
    234. for(i = 0; i < moveCount[k]; ++i) {
    235. printf("%c", moves[k][i] + 'A');
    236. }
    237. putchar('\n');
    238. }
    239. printf("%d\n", moveType[k]);
    240. }
    241. return 0;
    242. }

    错误的剪枝策略:(不要使用))

    1. // 错误的剪枝策略,
    2. bool shouldMove(int num, int step) {
    3. switch(step) {
    4. case 0:
    5. if(arrCon[0][5] == num || arrCon[0][6] == num || arrCon[0][4] == num) return true;
    6. break;
    7. case 1:
    8. if(arrCon[1][5] == num || arrCon[1][6] == num || arrCon[1][4] == num) return true;
    9. break;
    10. case 2:
    11. if(arrCon[2][0] == num || arrCon[2][1] == num || arrCon[2][2] == num) return true;
    12. break;
    13. case 3:
    14. if(arrCon[3][0] == num || arrCon[3][1] == num || arrCon[3][2] == num) return true;
    15. break;
    16. case 4:
    17. if(arrCon[1][0] == num || arrCon[1][1] == num || arrCon[1][2] == num) return true;
    18. break;
    19. case 5:
    20. if(arrCon[0][0] == num || arrCon[0][1] == num || arrCon[0][2] == num) return true;
    21. break;
    22. case 6:
    23. if(arrCon[3][5] == num || arrCon[3][6] == num || arrCon[3][4] == num) return true;
    24. break;
    25. case 7:
    26. if(arrCon[2][5] == num || arrCon[2][6] == num || arrCon[2][4] == num) return true;
    27. break;
    28. }
    29. return false;
    30. }

  • 相关阅读:
    智能巡检软件怎么选?企业设备管理需要做什么?
    [附源码]Python计算机毕业设计Django个性化产品服务管理系统论文
    基于时空注意力融合网络的城市轨道交通假期短时客流预测
    HBase学习笔记
    全球元宇宙市场投融资总额超320亿元 资本争相涌入 元宇宙探索仍在路上
    聊天、会议、多媒体一体化:多平台支持的即时通讯系统 | 开源日报 No.44
    亚马逊云科技顾凡解读云计算助力初创快速抢滩生成式AI新风口
    主流网络协议
    负载均衡的算法(静态算法与动态算法)
    B032-服务器 Tomcat JavaWeb项目 Servlet
  • 原文地址:https://blog.csdn.net/qq278672818/article/details/132932231