USACO 3.2.5 Magic Squares

看到题目,必然是宽搜无疑了

主要是对于状态的储存方法,一开始我很脑残的用 9 进制数来存状态,写到一半发现内存会超。。

重新考虑下,因为最多只有 8! 种状态,所以直接存每种状态有没有出现过是可行的。

TRANS 函数将每个状态映射到一个数(按 1 到 8 的全排列 从小到大顺序第 k 个, 就把当前状态映射到 k )

比如 1 2 3 4 5 6 7 8 映射到 1, 2 1 3 4 5 6 7 8 映射到 7! + 1 


状态的转换我是直接对数进行操作, 若当前状态为1 2 3 4 5 6 7 8, 就 看做一个数 12345678。

思想就是提取每一位的数字重新组合成新数,具体实现见代码,应该还是比较好理解的。


/*
PROG:msquare
LANG:C++
*/

#include <cstdio>
#include <cstring>

using namespace std;

const int N = 500000;
const int initial = 12345678;
const int digit[8] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000};
const int fac[8] = {1, 1, 2, 6, 24, 120, 720, 5040};
bool hash[50000], used[10];
int pre[N], a[N], ans[N], goal, tot, head, tail, x, now;
char change[N];

int transA(int now)
{
    int tmp = 0;
    tmp += (now % digit[1] * digit[7]);
    tmp += (now / digit[1] % digit[1] * digit[6]);
    tmp += (now / digit[2] % digit[1] * digit[5]);
    tmp += (now / digit[3] % digit[1] * digit[4]);
    tmp += (now / digit[4] % digit[1] * digit[3]);
    tmp += (now / digit[5] % digit[1] * digit[2]);
    tmp += (now / digit[6] % digit[1] * digit[1]);
    tmp += (now / digit[7] % digit[1] * digit[0]);
    return tmp;
}

int transB(int now)
{
    int tmp = 0;
    tmp += (now / digit[4] % digit[1] * digit[7]);
    tmp += (now / digit[5] * digit[4]);
    tmp += (now % digit[3] * digit[1]);
    tmp += (now / digit[3] % digit[1]);
    return tmp;
}

int transC(int now)
{
    int tmp = 0;
    tmp += (now / digit[7] * digit[7]);
    tmp += (now / digit[1] % digit[1] * digit[6]);
    tmp += (now / digit[6] % digit[1] * digit[5]);
    tmp += (now / digit[3] % digit[2] * digit[3]);
    tmp += (now / digit[5] % digit[1] * digit[2]);
    tmp += (now / digit[2] % digit[1] * digit[1]);
    tmp += (now % digit[1]);
    return tmp;
}

int trans(int now, int step)
{
    if (step == 0) return 1;
    int tmp = now / digit[step];
    int cnt = 0;
    for (int i = 1;i != tmp;++i)
    {
        if (!used[i])
            ++cnt;
    }
    used[tmp] = 1;
    return cnt * fac[step] + trans(now % digit[step], step-1);
}
int main()
{
    freopen("msquare.in", "r", stdin);
    freopen("msquare.out", "w", stdout);
    for (int i = 0;i < 8;++i)
    {
        scanf("%d", &x);
        goal = goal * 10 + x;
    }
    head = 0, tail = 1;
    a[head] = initial;
    while (head < tail)
    {
        memset(used, 0, sizeof(used));
        now = a[head++];
        int tmp = trans(now, 7);
        if (now == goal) break;
        if (hash[tmp]) continue;
        change[tail] = 'A', pre[tail] = head-1, a[tail++] = transA(now);
        change[tail] = 'B', pre[tail] = head-1, a[tail++] = transB(now);
        change[tail] = 'C', pre[tail] = head-1, a[tail++] = transC(now);
        hash[tmp] = 1;
    }
    int k = head-1;
    while (k != 0)
    {
        ans[++tot] = change[k];
        k = pre[k];
    }
    printf("%d\n", tot);
    for (int i = tot;i > 0;--i) printf("%c", ans[i]);
    printf("\n");
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值