HDU 1043 Eight

题目链接:Eight

解题思路:原来不知道,这是有名的8数码问题,它还用和15数码来废话半天。看了眼过的人数,直接BFS肯定就T了,况且,状态总数是9!, 36W,我怎么都不会估算复杂度了,这不是很少的状态么怎么还会TLE。

后来有人说打表,就是从终点向其他状态扩展同时记录操作序列,然后全部存到map里面,我看也有人用康托展开就存下了,其实map更简单。

还有无解的情况,其实就是逆序数的问题,终止节点的逆序数是0,然后你用空白节点和左右两边交换的话逆序数是不变的,那就只有上下了


我们分析a b c *这种情况,另一种是相反的。a和*互换

大小顺序

a   b   c

+2 0   0

a   c   b

+2 0  0

b   a   c

-1 +1 0

b   c   a

-1 -1  0

c   a   b

-1  +1   0

c   b  a

-1  -1  0

我们看到逆序数只有+2,+0,-2所以,逆序数只能为偶数,这也就是题目上面为什么说交换之后就无解了,那是因为交换两个相邻的数的话,逆序数不是+1就是-1,会从偶数变到奇数,从奇数变到偶数。就成无解了。


这是我在线打表的程序,打表差不多要650+MS左右。


#include<cstdio>
#include<map>
#include<queue>
#include<string>
#include<iostream>

using namespace std;

struct node{
    int s, idx;
    string seq;
    node(){}
    node(int ss, int iidx, string sseq){
        s = ss, seq = sseq, idx = iidx;
    }
};

int pp[10] = {1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
map<int, string> ans;
string put[4] = {"d","u","r","l"};
int dir[9][4] = {{-1,3,-1,1},{-1,4,0,2},{-1,5,1,-1},{0,6,-1,4},{1,7,3,5},{2,8,4,-1},{3,-1,-1,7},{4,-1,6,8},{5,-1,7,-1}};

int getA(int s, int idx){
    return s / pp[idx] % 10;
}

int change(int s, int a, int b){
    a = 8 - a;
    b = 8 - b;
    int tem = getA(s, a);
    s -= tem * pp[a];
    s += getA(s, b) * pp[a];
    s -= getA(s, b) * pp[b];
    s += tem * pp[b];
    return s;
}

void bfs(){
    int i, j, k;
    queue<node> mq;
    mq.push(node(123456789, 8, ""));
    ans[123456789] = "YES";
    while(!mq.empty()){
        node s = mq.front();
        //cout << s.s << " " << s.idx << " " << s.seq << endl;
        mq.pop();
        for(i = 0; i < 4; i++){
            int ss = s.s;
            int ii = s.idx;
            string qq = s.seq;
            qq += put[i];
            int tem = dir[ii][i];
            if(tem == -1)   continue;
            ss = change(ss, tem, ii);
            if(ans[ss] == ""){
                ans[ss] = qq;
                mq.push(node(ss, tem, qq));
            }
        }
    }

}

char ac[100];

int main(){
    int i, j, k;
   // freopen("1.out", "w", stdout);
   //freopen("1.in", "r", stdin);
    bfs();
    /*for(map<int, string>::iterator  it = ans.begin(); it != ans.end(); it++){
        cout << it->first << " " << it->second << endl;
    }*/
    while(gets(ac)){
        int s = 0, tot = 0;
        for(i = 0; tot < 9; i++){
            if(ac[i] >= '1' && ac[i] <= '8'){
                s = s * 10 + ac[i] - '0';
                tot++;
            }
            if(ac[i] == 'x'){
                s = s * 10 + 9;
                tot++;
            }
        }
        if(ans[s] == "YES"){
            puts("");
        }
        else if(ans[s] == ""){
            puts("unsolvable");
        }
        else{
            string tem = ans[s];
            for(i = tem.length() - 1; i >= 0; i--){
                printf("%c", tem[i]);
            }
            printf("\n");
        }
    }
    return 0;
}

还有一种启发式搜索的方法,2000+MS内搞定。

你可能感兴趣的:(bfs,打表,好题)