题目描述:
Dice
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2497 Accepted Submission(s): 1236Problem Description
There are 2 special dices on the table. On each face of the dice, a distinct number
was written. Consider a1.a2,a3,a4,a5,a6 to be numbers written on top face, bottom
face, left face, right face, front face and back face of dice A. Similarly, consider
b1.b2,b3,b4,b5,b6 to be numbers on specific faces of dice B. It’s guaranteed that all
numbers written on dices are integers no smaller than 1 and no more than 6 while
ai ≠ aj and bi ≠ bj for all i ≠ j. Specially, sum of numbers on opposite faces may not be 7.
At the beginning, the two dices may face different(which means there exist some i, ai ≠ bi).Ddy wants to make the two dices look the same from all directions(which means for
all i, ai = bi) only by the following four rotation operations.(Please read the picture
for more information)
Now Ddy wants to calculate the minimal steps that he has to take to achieve his goal.Input
There are multiple test cases. Please process till EOF.
For each case, the first line consists of six integers a1,a2,a3,a4,a5,a6, representing thenumbers on dice A.
The second line consists of six integers b1,b2,b3,b4,b5,b6, representing the numbers ondice B.
Output
For each test case, print a line with a number representing the answer. If there’s no way to
make two dices exactly the same, output -1.
Sample Input
1 2 3 4 5 6
1 2 3 4 5 61 2 3 4 5 6
1 2 5 6 4 31 2 3 4 5 6
1 4 2 5 3 6Sample Output
0
3
-1
题意:
给出两颗筛子,问最少经过几步能使两颗筛子的状态遗址,并输出最小步数,
若这两颗是完全不同的筛子,输出-1。每次变化如图四种方式。
思路:
自己一开始想的是模拟变化的过程,但是巨复杂,且最优解选择方案的正确性
既不好确定确定了也不好证明其正确性。
大佬一看就是搜索,自己对bfs的认识因为惯性思维一直停留图论中在矩阵或者网格图
上找最短路上,实际上很多与图没有直接联系的实际问题都可以抽象成图来解决,比如本题,
就是给出初始状态和终止状态,每种状态可以转移到四种状态,问起始状态到达终止状态的
最小步数/短路径,再比如19暑假晚上做过的一道文本光标移动的题目(一眼也是认为是模拟,
同样经过他人提醒之后才恍然大悟)。
然后本题的另一个难点在于怎么表示这24种状态(一个筛子最多24种状态)。首先想到的
是hash一下。然后状态转移时先反hash运算,然后再hash,hash用基数可以用10,因为这里
只有6个数字且0~5连续,所以基数可以用6。另外要注意的是本题vis的数组如果卡着hash值上
限开恰好可以过,但如果不小心开大了,加上多组的T(隐含),vis的清空是会超时的。
但是每一组数据,我们所用到的最多只有24个状态,也就是每次只需要清空这24个值即可,
大佬的解决方案是用一个数字记录上一组数据中使用过的状态,再在下一组数据中清空。
代码实现:
#include <iostream>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#define LL long long
#define inf 0x3f3f3f3f
#define ull unsigned long long
using namespace std;
const int N = 2e5+100;
//状态转移数组用法
int xx[][6]= {
{3,2,0,1,4,5},
{2,3,1,0,4,5},
{5,4,2,3,0,1},
{4,5,2,3,1,0}
};
//注意hash与反hash的对应关系
//要对应,别弄反了
int has(int *a) {
int res=0;
for(int i=5; i>=0; i--) {
res=res*6+a[i];
}
return res;
}
void zh(int x,int *a) {
for(int i=0; i<=5; i++) {
a[i]=x%6;
x/=6;
}
}
int a[6],b[6],c[6],vis[666667];
int used[666667],ucnt;
queue<int>qc;
int bfs(int bx,int ex) {
if(bx==ex)return 0;
//memset(vis,-1,sizeof(vis));//数组开的太大
while(ucnt) {
vis[used[ucnt]]=-1;
ucnt--;
}
while(qc.size())qc.pop();
vis[bx]=0;
used[++ucnt]=bx;
qc.push(bx);
while(qc.size()) {
int x=qc.front();
qc.pop();
zh(x,a);
for(int i=0; i<4; i++) {
for(int j=0; j<6; j++)
c[j]=a[xx[i][j]];
int id=has(c);
if(id==ex)return vis[x]+1;
if(vis[id]!=-1)continue;
vis[id]=vis[x]+1;
used[++ucnt]=id;
qc.push(id);
}
}
return -1;
}
int main() {
#ifdef MYHOME_Wjvje
freopen("input.txt","r",stdin);
#endif
int cas=0;
ucnt=0;//ucnt不要再while中置0
memset(vis,-1,sizeof(vis));//注意初始化一下
while(scanf("%d",&a[0])!=EOF) {
//if(++cnt*666667>=1e9)
//cout<<"-666"<<endl;//TLE测试
a[0]--;
for(int i=1; i<6; i++)
scanf("%d",&a[i]),a[i]--;
for(int i=0; i<6; i++)
scanf("%d",&b[i]),b[i]--;
printf("%d\n",bfs(has(a),has(b)));
}
return 0;
}
THE END;