标签:
Time Limit: 15000MS | Memory Limit: 150000KB | 64bit IO Format: %I64d & %I64u |
Description
Input
Output
Sample Input
1 1 1 1 3 2 3 2 3 1 3 2 2 3 1 2 2 2 3 1 2 1 3 3 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 0
Sample Output
AC 2 DDHH 2
Source
略可怕的题,肝了两个多小时,最后还是看了提示才过。
这种翻来倒去求操作方式的题明显是搜索题,因为这道题里状态实在不好保存,没法BFS,那么就选DFS。我开了个二维数组,像存图一样模拟井字存了数字,光读入就用了好多行
你以为到这里就结束了吗?不!
这个井字总共有8种操作方式,且没有统一的公式,得把8种都写上!为了状态回溯,还得写8行求回溯操作的代码。另外判断是否符合条件还要写8行。这些处理完以后,就可以开始搜索了。
你以为之后就简单了吗?不!才刚刚开始!
开始搜索吧,先写好状态改变、存解、判断是否出解、进入深层搜索、状态回溯……很好,程序陷入死循环了,DFS撑不住这题超大的深度。
那么剪枝吧,在尝试了类似限制连续同种操作次数、限制总深度、用随机数限制深度等方法之后,最终想到了迭代加深搜索。啊,迭代加深太棒了,很快就出了解。
你以为可以AC了吗?不!麻烦的还在后头!
虽然过了样例,但接着是花式TLE。这时我想起了隔壁Orion_Rigel的提示:A星算法。
TM我根本不会A星啊!果断百度搜A星,然而并没有找到好用的教程,仍旧一脸懵。最后怒看题解,噫,秒懂。总之就是根据“当前的操作状况和预估的需要操作次数”决策是否剪枝(看代码更好理解)
。于是把判断函数加上了预估功能(返回相等数字个数,而不是“是否都相等”)。
Accepted
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<cmath> 6 using namespace std; 7 int mp[8][8]; 8 int mini; 9 int ans[350]; 10 int ansnum=0; 11 int len=0; 12 int depth=0; 13 14 //dfs 15 int num_cnt[4];//数字出现次数 16 17 // 18 inline bool read(){//读入 19 scanf("%d",&mp[1][3]); 20 if(mp[1][3]==0)return false; 21 scanf("%d",&mp[1][5]); 22 scanf("%d%d",&mp[2][3],&mp[2][5]); 23 for(int i=1;i<=7;i++)scanf("%d",&mp[3][i]); 24 scanf("%d%d",&mp[4][3],&mp[4][5]); 25 for(int i=1;i<=7;i++)scanf("%d",&mp[5][i]); 26 scanf("%d%d",&mp[6][3],&mp[6][5]); 27 scanf("%d%d",&mp[7][3],&mp[7][5]); 28 return true; 29 } 30 void mv(int a){//模拟数字变换 31 switch(a){ 32 case 1:{//‘A‘ 33 int temp=mp[1][3]; 34 for(int i=1;i<=6;i++)mp[i][3]=mp[i+1][3]; 35 mp[7][3]=temp; 36 break; 37 } 38 case 2:{//‘B‘ 39 int temp=mp[1][5]; 40 for(int i=1;i<=6;i++)mp[i][5]=mp[i+1][5]; 41 mp[7][5]=temp; 42 break; 43 } 44 case 3:{//‘C‘ 45 int temp=mp[3][7]; 46 for(int i=7;i>=2;i--)mp[3][i]=mp[3][i-1]; 47 mp[3][1]=temp; 48 break; 49 } 50 case 4:{//‘D‘ 51 int temp=mp[5][7]; 52 for(int i=7;i>=2;i--)mp[5][i]=mp[5][i-1]; 53 mp[5][1]=temp; 54 break; 55 } 56 case 5:{//‘E‘ 57 int temp=mp[7][5]; 58 for(int i=7;i>=2;i--)mp[i][5]=mp[i-1][5]; 59 mp[1][5]=temp; 60 break; 61 } 62 case 6:{//‘F‘ 63 int temp=mp[7][3]; 64 for(int i=7;i>=2;i--)mp[i][3]=mp[i-1][3]; 65 mp[1][3]=temp; 66 break; 67 } 68 case 7:{//‘G‘ 69 int temp=mp[5][1]; 70 for(int i=1;i<=6;i++)mp[5][i]=mp[5][i+1]; 71 mp[5][7]=temp; 72 break; 73 } 74 case 8:{//‘H‘ 75 int temp=mp[3][1]; 76 for(int i=1;i<=6;i++)mp[3][i]=mp[3][i+1]; 77 mp[3][7]=temp; 78 break; 79 } 80 } 81 return; 82 } 83 int pd(){//判断中间相同数字最多个数,8个即是相同了 84 memset(num_cnt,0,sizeof(num_cnt)); 85 num_cnt[mp[3][3]]++; 86 num_cnt[mp[3][4]]++; 87 num_cnt[mp[3][5]]++; 88 num_cnt[mp[4][3]]++; 89 num_cnt[mp[4][5]]++; 90 num_cnt[mp[5][3]]++; 91 num_cnt[mp[5][4]]++; 92 num_cnt[mp[5][5]]++; 93 return max(num_cnt[1],max(num_cnt[2],num_cnt[3]));//返回中心出现最多的数 94 } 95 int reset(int i){//返回还原操作的序号 96 if(i<=4){ 97 if(i==1)return 6; 98 if(i==2)return 5; 99 if(i==3)return 8; 100 if(i==4)return 7; 101 } 102 else{ 103 if(i==5)return 2; 104 if(i==6)return 1; 105 if(i==7)return 4; 106 if(i==8)return 3; 107 } 108 return 0; 109 } 110 bool dfs(int t,int last){ 111 if(depth-t<8-pd()) return false; 112 //预测值剪枝 113 if(t>=depth) return false; 114 //最优值剪枝 115 for(int i=1;i<=8;i++){ 116 if(i==reset(last))continue;//防止和上一步反向移动 117 mv(i);//移动 118 ans[t]=i; 119 if(pd()==8){//出解 120 len=t; 121 ansnum=mp[3][3]; 122 return true; 123 } 124 if(dfs(t+1,i))return true;//下一层 125 mv(reset(i));//还原 126 } 127 return false; 128 } 129 int main(){ 130 while(read()){ 131 int i,j; 132 if(pd()==8){ 133 printf("No moves needed\n"); 134 printf("%d\n",mp[3][3]); 135 } 136 else{ 137 depth=1; 138 while(1){ 139 if(dfs(1,-1))break; 140 // printf("Dep:%d\n",depth); 141 depth++;//迭代加深 142 } 143 for(int i=1;i<=len;i++)printf("%c",(char)ans[i]+‘A‘-1); 144 printf("\n"); 145 printf("%d\n",ansnum); 146 } 147 } 148 return 0; 149 }
标签:
原文地址:http://www.cnblogs.com/SilverNebula/p/5559954.html