POJ 1077 Eight & HDU 1043 Eight(康托展开+BFS)

来源:互联网 发布:java 角色权限 编辑:程序博客网 时间:2024/05/20 06:27

题目链接:1077 -- Eight Problem - 1043

两个题目几乎完全一致。不同的是,HDU的八数码这道题需要一次bfs,起点为123456789X,遍历完所有状态,同时用pre数组记录上一个状态,然后每次输入只需要一个while进行O(1)的查询。

方法没有什么特殊的,我用的是普通的bfs。这道题和其他的搜索题目不一样的一点是,9个格子,太大没有办法标记。这时可以利用康托展开。

康托展开是一个完美hash函数,可以将n个数的所有排列组合状态进行压缩。9个数进行全排列,记录状态需要大小1e10的数组,经过康托展开的映射后只需要大小为9!的数组。一个数组经过这个过程,可以得到这个数组在全排列的序号。比如213是组合{1, 2, 3}中的第2小的组合(下标从0开始)。那么该如何得到213的康托展开就由1*2!+0*1!+0*0!得到。第一位是2,当第一位的数小于2时,排列数一定小于213,比如123、132,所以有1*2!,再看小于第二位1的,小于2的数没有 所以有0*1!=0,所以小于213的{1,2,3}排列数有1*2!+0*1!=2个,所以213是第3个大的数。


POJ 1077

#include <set>#include <map>#include <cmath>#include <stack>#include <queue>#include <vector>#include <string>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;#define FIN freopen("in.txt", "r", stdin);#define FOUT freopen("out.txt", "w", stdout);const int INF = 0x3f3f3f3f;const int MAXN = 400005;char op[MAXN];int pre[MAXN], fac[55];bool vis[MAXN], flag;int CantorExpansion(LL m){    int str[10], pos = 8;    while (m)    {        str[pos--] = m % 10;        m /= 10;    }    int ret = 0;    for (int i = 0; i < 8; i++)    {        int tmp = 0;        for (int j = i + 1; j < 9; j++)            if (str[i] > str[j])                tmp++;        ret += tmp * fac[8 - i];    }    return ret;}void bfs(LL start){    memset(vis, false, sizeof(vis));    memset(op, -1, sizeof(op));    queue<LL> q;    int id;    q.push(start);    id = CantorExpansion(start);    vis[id] = true;    while (!q.empty())    {        LL cur = q.front();        q.pop();        if (cur == 123456789)        {            stack<char> sta;            id = CantorExpansion(cur);            while (op[id] != -1)            {                sta.push(op[id]);                id = pre[id];            }            while (!sta.empty())            {                printf("%c", sta.top());                sta.pop();            }            puts("");            flag = true;            return;        }        int str[10], pos = 8, nine;        LL tcur = cur;        while (tcur)        {            if (tcur % 10 == 9)                nine = pos;            str[pos--] = tcur % 10;            tcur /= 10;        }        for (int i = 0; i < 4; i++)        {            if ((i == 0 && nine / 3 == 0) || (i == 1 && nine / 3 == 2) || (i == 2 && nine % 3 == 0) || (i == 3 && nine % 3 == 2))                continue;            int tstr[10];            memcpy(tstr, str, 9 * sizeof(int));            if (i == 0)                swap(tstr[nine], tstr[nine - 3]);            else if (i == 1)                swap(tstr[nine], tstr[nine + 3]);            else if (i == 2)                swap(tstr[nine], tstr[nine - 1]);            else if (i == 3)                swap(tstr[nine], tstr[nine + 1]);            LL tt = 0;            for (int i = 0; i < 9; i++)                tt = tt * 10 + tstr[i];            int id = CantorExpansion(tt);            if (!vis[id])            {                if (i == 0)                    op[id] = 'u';                else if (i == 1)                    op[id] = 'd';                else if (i == 2)                    op[id] = 'l';                else if (i == 3)                    op[id] = 'r';                pre[id] = CantorExpansion(cur);                vis[id] = true;                q.push(tt);            }        }    }}int main(){#ifndef ONLINE_JUDGE    FIN;#endif // ONLINE_JUDGE    //bfs();    fac[0] = fac[1] = 1;    for (int i = 2; i < 9; i++)        fac[i] = fac[i - 1] * i;    char str[50];    while (gets(str))    {        flag = false;        int s = 0;        for (int i = 0; str[i]; i++)        {            if (str[i] == 'x')                s = s * 10 + 9;            else if (str[i] != ' ')                s = s * 10 + str[i] - '0';        }        int id = CantorExpansion(s);        if (id == 0)        {            printf("lr\n");            continue;        }        bfs(s);        if (!flag)            printf("unsolvable\n");    }    return 0;}


HDU 1043

#include <set>#include <map>#include <cmath>#include <stack>#include <queue>#include <vector>#include <string>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;#define FIN freopen("in.txt", "r", stdin);#define FOUT freopen("out.txt", "w", stdout);const int INF = 0x3f3f3f3f;const int MAXN = 400005;char op[MAXN];int pre[MAXN], fac[55];bool vis[MAXN];int CantorExpansion(LL m){    int str[10], pos = 8;    while (m)    {        str[pos--] = m % 10;        m /= 10;    }    int ret = 0;    for (int i = 0; i < 8; i++)    {        int tmp = 0;        for (int j = i + 1; j < 9; j++)            if (str[i] > str[j])                tmp++;        ret += tmp * fac[8 - i];    }    return ret;}void bfs(){    fac[0] = fac[1] = 1;    for (int i = 2; i < 9; i++)        fac[i] = fac[i - 1] * i;    memset(vis, false, sizeof(vis));    memset(op, -1, sizeof(op));    queue<LL> q;    int id;    q.push(123456789);    id = CantorExpansion(123456789);    vis[id] = true;    while (!q.empty())    {        LL cur = q.front();        q.pop();        int str[10], pos = 8, nine;        LL tcur = cur;        while (tcur)        {            if (tcur % 10 == 9)                nine = pos;            str[pos--] = tcur % 10;            tcur /= 10;        }        for (int i = 0; i < 4; i++)        {            if ((i == 0 && nine / 3 == 0) || (i == 1 && nine / 3 == 2) || (i == 2 && nine % 3 == 0) || (i == 3 && nine % 3 == 2))                continue;            int tstr[10];            memcpy(tstr, str, 9 * sizeof(int));            if (i == 0)                swap(tstr[nine], tstr[nine - 3]);            else if (i == 1)                swap(tstr[nine], tstr[nine + 3]);            else if (i == 2)                swap(tstr[nine], tstr[nine - 1]);            else if (i == 3)                swap(tstr[nine], tstr[nine + 1]);            LL tt = 0;            for (int i = 0; i < 9; i++)                tt = tt * 10 + tstr[i];            int id = CantorExpansion(tt);            if (!vis[id])            {                if (i == 0)                    op[id] = 'd';                else if (i == 1)                    op[id] = 'u';                else if (i == 2)                    op[id] = 'r';                else if (i == 3)                    op[id] = 'l';                pre[id] = CantorExpansion(cur);                vis[id] = true;                q.push(tt);            }        }    }}int main(){#ifndef ONLINE_JUDGE    FIN;#endif // ONLINE_JUDGE    bfs();    char str[50];    while (gets(str))    {        int s = 0;        for (int i = 0; str[i]; i++)        {            if (str[i] == 'x')                s = s * 10 + 9;            else if (str[i] != ' ')                s = s * 10 + str[i] - '0';        }        int id = CantorExpansion(s);        if (id == 0)        {            printf("lr\n");            continue;        }        if (op[id] == -1)        {            printf("unsolvable\n");            continue;        }        while (id != 0)        {            printf("%c", op[id]);            id = pre[id];        }        puts("");    }    return 0;}


0 0