USACO msquare (BFS+康托展开)

     这是个简单题。一看就是用队列来BFS,因为1-8八个数字的全排列有8!=40320种。唯一需要解决的问题就是怎么把8个数字的每种不同的排列映射到唯一的整数上,因为如果用一个大小为[87654321]数组,浪费了大量的存储空间,必定导致超内存。找到一个叫“康托展开”的东东,真是惭愧啊,很简单的东西,其实自己应该都能想到才对。很简单的思想:把每种排列映射为该排列在全排列中的次序即可。

 

/*
ID: morgan_xww
LANG: C
TASK: msquare
*/

#include <stdio.h>
#include <string.h>

struct
{
    int  vlu;
    int  cnt;
    int  pre;
    char tsf;
} Q[50000];

int  fac[9] = {1,1,2,6,24,120,720,5040,40320};
int  Target, Qnum, p;
char vst[50000];

int KT(int s[]) //康托展开
{
    int i, j, t, sum;
    sum = 0;
    for (i=0; i<8; i++)
    {
        t = 0;
        for (j=i+1; j<8; j++)
            if (s[j] < s[i])
                t++;
        sum += t*fac[7-i];
    }
    return sum+1;
}

void invKT(int n, int s[]) //康托展开的逆运算
{
    int i, j, t, vst[8]={0};
    n--;
    for (i=0; i<8; i++)
    {
        t = n/fac[7-i];
        for (j=1; j<=8; j++)
            if (!vst[j])
            {
                if (t == 0) break;
                t--;
            }
        s[i] = j;
        vst[j] = 1;
        n %= fac[7-i];
    }
}

void PrintAns()
{
    int  i, k;
    char ans[50000];

    k = Qnum-1;
    printf("%d", Q[k].cnt);
    i = 0;
    while (Q[k].cnt)
    {
        ans[i++] = Q[k].tsf;
        k = Q[k].pre;
    }
    k = 0;
    while (--i >= 0)
    {
        if (k%60 == 0)
            printf("/n");
        printf("%c", ans[i]);
        k++;
    }
    printf("/n");
    exit(0);
}

void AddQue(int k, char ch) //加入队列
{
    if (!vst[k])
    {
        Q[Qnum].vlu = k;
        Q[Qnum].cnt = Q[p].cnt+1;
        Q[Qnum].pre = p;
        Q[Qnum].tsf = ch;
        Qnum++;
        vst[k] = 1;
    }
    if (k == Target)
        PrintAns();
}

void Transf(int s[]) //三种变换
{
    int i, t[8];
    // A变换
    for (i=0; i<8; i++) t[i] = s[7-i];
    AddQue(KT(t), 'A');
    // B变换
    t[0] = s[3];
    t[7] = s[4];
    for (i=1; i<=3; i++) t[i] = s[i-1];
    for (i=4; i<=6; i++) t[i] = s[i+1];
    AddQue(KT(t), 'B');
    // C变换
    t[0] = s[1];
    s[1] = s[6];
    s[6] = s[5];
    s[5] = s[2];
    s[2] = t[0];
    AddQue(KT(s), 'C');
}

void BFS()
{
    int s[8];
    p = 0;
    while (p < Qnum)
    {
        invKT(Q[p].vlu, s);
        Transf(s);
        p++;
    }
}

int main()
{
    //freopen("msquare.in", "r", stdin);
    //freopen("msquare.out", "w", stdout);

    int  i, t;
    int  stat[8]={1,2,3,4,5,6,7,8};
    int  targ[8];

    for (i=0; i<8; i++)
        scanf("%d", &targ[i]);
    Target = KT(targ);
    t = KT(stat);
    if (t == Target)
    {
        printf("0/n/n");
        exit(0);
    }
    Q[0].vlu = t;
    Q[0].cnt = 0;
    Qnum = 1;
    vst[t] = 1;
    BFS();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值