P2730 魔板 Magic Squares

不看题解肯定不会系列。。。


这道题可以用Cantor展开解决。

Cantor展开可以求出一个数组是在全排列中的第几个。

具体怎么操作自己百度。

Cantor展开的公式是:\(a[1] * (n - 1)! + a[2] * (n - 2)! + ... + a[n] * 0!\)

这里注意一下:\(0!=1\)

其中\(a[i]\)表示第\(i\)个数在\([i, n]\)这个区间的第几大(最小为\(0\),最大为\(n - i\))。

这样求出来的数字取值范围是在\([0, n! - 1]\)。你愿意的话可以一起+1。

这样的话,对于这个魔板的状态,就可以套用Cantor展开,用\(8!\)的空间就可以存下来,如果不用的话需要一亿。

然后我们可以用Cantor展开的值当下标,就可以精确无误地取出每一个状态。

代码:

#include<cstdio>
#include<vector>
const int aa[] = {0, 8, 7, 6, 5, 4, 3, 2, 1};
const int bb[] = {0, 4, 1, 2, 3, 6, 7, 8, 5};
const int cc[] = {0, 1, 7, 2, 4, 5, 3, 6, 8};
const int frac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320};
struct Nodes
{
    int fa;
    int a[9];
    int dist;
    char how;
    bool mark;
} s[50005];
int end[9], end_cantor;
int queue[50005], front, rear;
int cantor(int* a)
{
    int ans = 0;
    for(int i = 1; i <= 8; i++)
    {
        int s = 0;
        for(int j = i + 1; j <= 8; j++)
        {
            if(a[i] > a[j]) s++;
        }
        ans += s * frac[8 - i];
    }
    return ans + 1;
}
Nodes changeA(Nodes x)
{
    Nodes ans;
    for(int i = 1; i <= 8; i++) ans.a[i] = x.a[aa[i]];
    return ans;
}
Nodes changeB(Nodes x)
{
    Nodes ans;
    for(int i = 1; i <= 8; i++) ans.a[i] = x.a[bb[i]];
    return ans;
}
Nodes changeC(Nodes x)
{
    Nodes ans;
    for(int i = 1; i <= 8; i++) ans.a[i] = x.a[cc[i]];
    return ans;
}
int bfs()
{
    for(int i = 1; i <= 8; i++) s[1].a[i] = i;
    queue[rear++] = 1; s[1].mark = true;
    while(front < rear)
    {
        int x = queue[front++];
        if(x == end_cantor) return s[x].dist;
        Nodes A = changeA(s[x]); int A_cantor = cantor(A.a);
        Nodes B = changeB(s[x]); int B_cantor = cantor(B.a);
        Nodes C = changeC(s[x]); int C_cantor = cantor(C.a);
        if(!s[A_cantor].mark)
        {
            s[A_cantor] = A;
            s[A_cantor].dist = s[x].dist + 1;
            s[A_cantor].fa = x;
            s[A_cantor].how = 'A';
            queue[rear++] = A_cantor; s[A_cantor].mark = true;
            
        }
        if(!s[B_cantor].mark)
        {
            s[B_cantor] = B;
            s[B_cantor].dist = s[x].dist + 1;
            s[B_cantor].fa = x;
            s[B_cantor].how = 'B';
            queue[rear++] = B_cantor; s[B_cantor].mark = true;
        }
        if(!s[C_cantor].mark)
        {
            s[C_cantor] = C;
            s[C_cantor].dist = s[x].dist + 1;
            s[C_cantor].fa = x;
            s[C_cantor].how = 'C';
            queue[rear++] = C_cantor; s[C_cantor].mark = true;
        }
    }
}
int main()
{
    for(int i = 1; i <= 8; i++) scanf("%d", &end[i]);
    end_cantor = cantor(end);
    printf("%d\n", bfs());
    std::vector<char> v;
    for(int i = end_cantor; i != 1; i = s[i].fa) v.push_back(s[i].how);
    for(int i = v.size() - 1; i >= 0; i--) printf("%c", v[i]);
    printf("\n");
    return 0;
}
posted @ 2018-07-22 16:32  Garen-Wang  阅读(120)  评论(0编辑  收藏  举报