HDU 5012 鞍山网络赛(隐式bfs,状态表示的技巧,超时避免的技巧)

题目描述:

Dice

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2497    Accepted Submission(s): 1236

Problem 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 the

numbers on dice A. 

The second line consists of six integers b1,b2,b3,b4,b5,b6, representing the numbers on

dice 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 6

1 2 3 4 5 6
1 2 5 6 4 3

1 2 3 4 5 6
1 4 2 5 3 6

Sample 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;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值