hdu1430 魔板(双向bfs+输出路径+字典序最小)



魔板

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1352    Accepted Submission(s): 270


Problem Description
在魔方风靡全球之后不久,Rubik先生发明了它的简化版——魔板。魔板由8个同样大小的方块组成,每个方块颜色均不相同,可用数字1-8分别表示。任一时刻魔板的状态可用方块的颜色序列表示:从魔板的左上角开始,按顺时针方向依次写下各方块的颜色代号,所得到的数字序列即可表示此时魔板的状态。例如,序列(1,2,3,4,5,6,7,8)表示魔板状态为:

1 2 3 4
8 7 6 5

对于魔板,可施加三种不同的操作,具体操作方法如下:

A: 上下两行互换,如上图可变换为状态87654321
B: 每行同时循环右移一格,如上图可变换为41236785
C: 中间4个方块顺时针旋转一格,如上图可变换为17245368

给你魔板的初始状态与目标状态,请给出由初态到目态变换数最少的变换步骤,若有多种变换方案则取字典序最小的那种。
 

Input
每组测试数据包括两行,分别代表魔板的初态与目态。
 

Output
对每组测试数据输出满足题意的变换步骤。
 

Sample Input
 
   
12345678 17245368 12345678 82754631
 

Sample Output
 
   
C AC
 

Author
LL
 

Source
ACM暑期集训队练习赛(三)
 

Recommend
linle
 
题目大意:中文题不解释。

题目分析:这题类似八数码,看完题分析了一下,8个位置每个位置9个状态,由于数字都不一样,判重用康托展开。

所以一共只有8!种状态,所以先拍了一个朴素的bfs,

结果华丽丽的TLE了,因为后台的case太多了。。单向不行那就双向吧。正好也练习一下双向bfs,

虽然这题只需要单向bfs预处理就可以很快过,但只是为了练习一下,

结果就走上了WA的不归路啊啊啊,整整跪了2天。最后感谢@FancyMouse    的帮助,找到了bug,终于过了啊啊啊啊。

这题双向bfs本来没那么复杂,不过要输出路径就有点复杂了,更dt的是还要字典序最小!!

方法是这样的,正向搜索很常规,直接搜就行了,按ABC依次扩展。flag[0][state]记录的是正向搜索从起点的

一条路径中state状态的前驱,那么op[0][state]记录的就是从state状态的前驱到state状态所用的操作。

反向也差不多,从终点依次向中间扩展,不过扩展的时候不是做相应的ABC操作,而是做ABC3种操作的逆操作,

即:A操作还是将字符串翻转,B操作就是每行左移1格了,C操作是中间4个左旋1格,这样有什么好处呢,

我们发现最后正反双向搜索搜到重复节点的时候要输出路径,这样的话我们直接从相遇点依次扫到终点,

扫出来的路径就是正向操作的路径。比如从终点逆向扩展2步CA到达某个倒数第二步,那么正着看,

从这个倒数第二步通过正常的AC操作也是能到达终点的。所以op[1][state]记录的就是从终点反向

扩展到state状态所用的逆操作,其实正着看就是从state状态往终点走的下一步的正向操作也是op[1][state]

flag[1][state]就是记录的state状态往终态走的后继状态,这样就能保证前后

2半都是字典序最小(想一想,为什么)。但是每找到一个解,不着急输出,不要着急跳出循环,

而是还要继续比较一下。我就是因为这一点长跪不起,

一直WA,因为搜索的过程中会有多解,比如这题的BCCC和ABCA就是效果相同的操作。

如果2个解是aaabbb和bbbaaa,并且在反向搜索的时候找到解,那么反向因为保证了字典序最小了,

所以反向会先扩展到aaa,找到解,如果直接

break显然有问题,

因为显然这个字典序不一定是最小的,显然没有考虑到前半段的结果。所以我们

找到解后不着急跳出来,只要标记上就可以了,把同一层的搜完,选出字典序最小的作为最优解。

代码写的比较臭比较长,但是比较清晰。

详情请见代码:

#include 
#include
#include
#include
using namespace std;
const int N = 1000005;
int flag[2][50000];
char op[2][50000];
long fac[] = {1,1,2,6,24,120,720,5040,40320,362880};
struct node
{
    int step,val;
    char state[10];
}ss,now,temp[N];
int tmpnum;

struct que
{
    struct node t[N];
    int head,tail;
    void init()
    {
        head = tail = 0;
    }
    bool empty()
    {
        return tail == head;
    }
    struct node top()
    {
        return t[head];
    }
    void push(struct node a)
    {
        t[tail] = a;
        tail ++;
        if(tail >= N)
            tail %= N;
    }
    void pop()
    {
        head ++;
        if(head >= N)
            head %= N;
    }
}q[2];
//queueq[2];
int contor()
{
    int i,j;
    long temp,num;
    num = 0;
    for(i = 0;i < 8;i ++)
    {
        temp = 0;
        for(j = i + 1;j < 8;j ++)
            if(ss.state[j] < ss.state[i])
                temp ++;
        num += temp * fac[8 - i - 1];
    }
    return num;
}

void change(int type)
{
    int i;
    char c;
    switch(type)
    {
        case 1:for(i = 0;i < 4;i ++)
                {
                    ss.state[i] ^= ss.state[7 - i];
                    ss.state[7 - i] ^= ss.state[i];
                    ss.state[i] ^= ss.state[7 - i];
                }
               break;
        case 2:c = ss.state[3];
                for(i = 3;i > 0;i --)
                    ss.state[i] = ss.state[i - 1];
                ss.state[i] = c;
                c = ss.state[4];
                for(i = 4;i < 7;i ++)
                    ss.state[i] = ss.state[i + 1];
                ss.state[i] = c;
                break;
        case 3:c = ss.state[1];
                ss.state[1] = ss.state[6];
                ss.state[6] = ss.state[5];
                ss.state[5] = ss.state[2];
                ss.state[2] = c;
                break;
    }
}

void change2(int type)
{
    int i;
    char c;
    switch(type)
    {
        case 1:for(i = 0;i < 4;i ++)
                {
                    ss.state[i] ^= ss.state[7 - i];
                    ss.state[7 - i] ^= ss.state[i];
                    ss.state[i] ^= ss.state[7 - i];
                }
               break;
        case 2:c = ss.state[0];
                for(i = 0;i < 3;i ++)
                    ss.state[i] = ss.state[i + 1];
                ss.state[i] = c;
                c = ss.state[7];
                for(i = 7;i > 4;i --)
                    ss.state[i] = ss.state[i - 1];
                ss.state[i] = c;
                break;
        case 3:c = ss.state[1];
                ss.state[1] = ss.state[2];
                ss.state[2] = ss.state[5];
                ss.state[5] = ss.state[6];
                ss.state[6] = c;
                break;
    }
}
char s1[10],s2[10];
int end,start;
char ans[50000];
char tans[5000];
char ttans[5000];
int ansnum;
void print()
{
    int i;
    int root = ss.val;
    int num = 0;
	tans[num ++] = op[0][ss.val];
    while(root != start)
    {
        root = flag[0][root];
		tans[num ++] = op[0][root];
    }
	int p = 0;
    for(i = num - 2;i >= 0;i --)
	{
        //printf("%c",ans[i]);
		ttans[p ++] = tans[i];
	}
    num = 0;
    root = ss.val;
	tans[num ++] = op[1][ss.val];
    while(root != end)
    {
		root = flag[1][root];
        tans[num ++] = op[1][root];
    }
    for(i = 0;i < num - 1;i ++)
	{
        //printf("%c",ans[i]);
		ttans[p ++] = tans[i];
	}
	ttans[p] = '\0';
	if(ansnum)
	{
		if(strcmp(ans,ttans) > 0)
			strcpy(ans,ttans);
	}
	else
		strcpy(ans,ttans);
	ansnum ++;//newans;
}


int main()
{
    int i,j;
    while(~scanf("%s%s",s1,s2))
    {
        if(strcmp(s1,s2) == 0)
        {
            puts("");
            continue;
        }
        q[0].init();
        q[1].init();
//        while(!q[0].empty())
//            q[0].pop();
//        while(!q[1].empty())
//            q[1].pop();
        memset(flag,-1,sizeof(flag));
        memset(op,0,sizeof(op));
        ss.step = 0;
        strcpy(ss.state,s1);
        start = contor();
        ss.val = start;
        flag[0][start] = start;
        q[0].push(ss);
        strcpy(ss.state,s2);
        end = contor();
        ss.val = end;
        flag[1][end] = end;
        q[1].push(ss);
        bool ok = false;
        i = 0;
		tmpnum = 0;
		ansnum = 0;
        while(!ok)
        {
            while(!q[0].empty() && q[0].top().step == i)
            {
                now = q[0].top();
                q[0].pop();
                ss = now;
                ss.step ++;
                change(1);
                ss.val = contor();
                if(flag[0][ss.val] == -1)
                {
                    flag[0][ss.val] = now.val;
                    op[0][ss.val] = 'A';
                    if(flag[1][ss.val] != -1)
                    {
                        print();
                        ok = true;
                        //break;//罪恶的break
                    }
                    q[0].push(ss);
                }
                ss = now;
                ss.step ++;
                change(2);
                ss.val = contor();
                if(flag[0][ss.val] == -1)
                {
                    flag[0][ss.val] = now.val;
                    op[0][ss.val] = 'B';
                    if(flag[1][ss.val] != -1)
                    {
                        print();
                        ok = true;
                        //break;//wa之源
                    }
                    q[0].push(ss);
                }
                ss = now;
                ss.step ++;
                change(3);
                ss.val = contor();
                if(flag[0][ss.val] == -1)
                {
                    flag[0][ss.val] = now.val;
                    op[0][ss.val] = 'C';
                    if(flag[1][ss.val] != -1)
                    {
                        print();
                        ok = true;
                        //break;//冷静分析
                    }
                    q[0].push(ss);
                }
            }
			if(ok)
				break;
            while(!q[1].empty() && q[1].top().step == i)
            {//先把同一层的一起出队,同时按ABC扩展,这样才能保证反向
                temp[tmpnum ++] = q[1].top();//字典序最小,
                q[1].pop();//如果不能理解,用笔在纸上画画就明白了
            }
            for(j = 0;j < tmpnum;j ++)
            {
                ss = temp[j];
                ss.step ++;
                change2(1);
                ss.val = contor();
                if(flag[1][ss.val] == -1)
                {
                    flag[1][ss.val] = temp[j].val;
                    op[1][ss.val] = 'A';
                    if(flag[0][ss.val] != -1)
                    {
                        print();
                        ok = true;
                       // break;//break要三思
                    }
                    q[1].push(ss);
                }
            }
            for(j = 0;j < tmpnum;j ++)
            {
                ss = temp[j];
                ss.step ++;
                change2(2);
                ss.val = contor();
                if(flag[1][ss.val] == -1)
                {
                    flag[1][ss.val] = temp[j].val;
                    op[1][ss.val] = 'B';
                    if(flag[0][ss.val] != -1)
                    {
                        print();
                        ok = true;
                       // break;//早该想到的
                    }
                    q[1].push(ss);
                }
            }
            for(j = 0;j < tmpnum;j ++)
            {
                ss = temp[j];
                ss.step ++;
                change2(3);
                ss.val = contor();
                if(flag[1][ss.val] == -1)
                {
                    flag[1][ss.val] = temp[j].val;
                    op[1][ss.val] = 'C';
                    if(flag[0][ss.val] != -1)
                    {
                        print();
                        ok = true;
                       // break;//。。。。
                    }
                    q[1].push(ss);
                }
            }
            tmpnum = 0;
            i ++;
			if(ok)
				break;
        }
        printf("%s\n",ans);
    }
    return 0;
}
//1234MS	820K
//625MS	924K 好吧,g++提交时间快了一倍。。。
/*
12345678
64572813
12345678
74381652
15874623
73841652
12345678
82754631
12345678
48136275

12345678
12345678
12345678
87654321
12345678
41236785
12345678
58763214
12345678
86354271
12345678
58632714
12345678
51863724
12345678
42736815

17638254
46273185
76253841
26387154
13578642
24687531
36718254
82716435
12345678
21345678

46753812
54387612
37521684
54137628
*/
CSDN的排版怎么回事啊啊啊。。。。

你可能感兴趣的:(#,搜索)