Vijos 1029 晴天小猪历险记之Number【BFS+康托展开】

Vijos 1029

背景
话说上一回,晴天小猪不畏千难万险、千辛万苦、千磨万难……终于爬上了那座深山,来到了那位隐者的小屋中,但它不知道,有一个问题正等待着它……
晴天小猪一推开门,就发现那里……空无一人?但在屋中央有一个石桌,上面有一些字(强吧),最大的几个:如要见我,先过了这道关再说!
晴天小猪定睛一看,终于发现桌上密密麻麻布满了字,费了九天二猪之力,终于将题目看完,大意是:为了维护世界的和平……我们需要让九位勇士组成一个3*3的阵型去屠龙,但是这个阵型的要求很奇特,要九个人按照强弱依次编号1~9,且阵型中每行、每列、每条长对角线上的数字和都为15,这样才能使龙对勇士和阵型收到的损害最小,但九位勇士光是争夺名次就开始翻脸,各位**(任君想象)忙得不可开交,但晴天小猪也急得不可开交(-_-|||),只好向你求助。

描述
现在假设九位勇士已编好了号(感觉好像有人盯着我……)并站好了位置,例如:
7 8 9
1 2 3
4 5 6
每一次交换都可以将相邻的两位勇士(也就是编号……)交换位置,例如:
7 9 8
1 2 3 (8与9交换)
4 5 6

7 8 9
4 2 3 (4与1交换)
1 5 6
但不能
7 8 9
5 2 3 (1与5交换)
4 1 6
求最少的交换次数,使得九位勇士能在最短的时间内(当然是他们争完后……)以最安全的阵型去屠龙。

P.S:由于不能预测未来,各位设想了许多的阵型(-_-||),所以给了你10组阵型(测试点),每组50个……

格式
输入格式
输入数据一共3*50行,每个数据中用3*3的9个不同的1~9的数字表示初始状态。

(样例就只给几个阵型了^_^)

输出格式
每行一个数,即对应的初始阵型到所需阵型所需最少的交换次数,如果无解,输出-1。

样例1
样例输入1
7 8 9
1 2 3
4 5 6
6 1 8
7 5 3
2 9 4
1 2 8
3 5 4
6 7 9
Copy
样例输出1
8
0
5
Copy
限制
各个测试点5s

提示
欲知后事如何,请做出此题^_^。

来源
Sunnypig

所有情况的总和是9!,在这个题目的时间限制范围内可以实现暴力搜索。
如果暴搜,需要标记每一个出现的状态,状态与实际字符串之间的转换可以通过康托展开转换成第几个数字来标记。这样一来,我们就把10^9的标记数组压缩至9!。如直接通过字符串与整型转换的话,按常理也可以AC。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#include<set>
#include<queue>
using namespace std;
//BFS+康托展开hash
//通过康托展开来实现一种hash操作。
#define ll long long int
const int maxn = 1e6 + 10;
char a[20], s[20];
int c[20];
int num[200];
int vis[maxn];
int fac[] = { 1,1,2,6,24,120,720,5040,40320 };//jiecheng
int kangtuo(int n, char a[]) {//已知数字求位置
    int i, j, t, sum;
    sum = 0;
    for (i = 0; i < n; i++) {
        t = 0;
        for (j = i + 1; j < n; j++) {
            if (a[i] > a[j]) ++t;

        }
        sum += t * fac[n - i - 1];
    }
    return sum + 1;
}
void reverse_kangtuo(int n, int k, char s[])//已知位置求数字
{

    //1~n的全排列,其中的第K个数为s[]
    int i, j, t, vst[13] = { 0 };
    --k;
    for (i = 0; i < n; i++) {
        t = k / fac[n - i - 1];
        for (j = 1; j <= n; j++) {
            if (!vst[j]) {
                if (!t) break;
                --t;
            }
        }
        s[i] = '0' + j;
        vst[j] = 1;
        k %= fac[n - i - 1];
    }
}
int check(char a[]) {
    for (int i = 0; i<9; i++) {
        c[i + 1] = a[i] - '0';
    }
    if (c[1] + c[2] + c[3] != 15 || c[4] + c[5] + c[6] != 15 || c[7] + c[8] + c[9] != 15) return 0;
    if (c[1] + c[4] + c[7] != 15 || c[2] + c[5] + c[8] != 15 || c[3] + c[6] + c[9] != 15) return 0;
    if (c[1] + c[5] + c[9] != 15 || c[3] + c[5] + c[7] != 15) return 0;
    return 1;
}
void bfs() {
    queue<int> q;
    q.push(kangtuo(9, a));
    vis[kangtuo(9, a)] = 0;
    while (!q.empty()) {
        int cs = q.front();
        q.pop();
        reverse_kangtuo(9, cs, s);
        if (check(s)) {
            printf("%d\n", vis[cs]); return;
        }
        for (int i = 0; i<6; i++) {
            swap(s[i], s[i + 3]);
            int tmp = kangtuo(9, s);
            if (vis[tmp] == -1) q.push(tmp), vis[tmp] = vis[cs] + 1;
            swap(s[i + 3], s[i]);
        }
        for (int i = 0; i<9; i++) {
            if (i % 3 == 2) continue;
            swap(s[i], s[i + 1]);
            int tmp = kangtuo(9, s);
            if (vis[tmp] == -1) q.push(tmp), vis[tmp] = vis[cs] + 1;
            swap(s[i + 1], s[i]);
        }
    }
}
int main()
{
    while (~scanf("%d", &c[0])) {
        for (int i = 1; i<9; i++) {
            scanf("%d", &c[i]);
        }
        for (int i = 0; i<9; i++) {
            a[i] = c[i] + '0';
        }
        memset(vis, -1, sizeof vis);
        bfs();
        //cout<<kangtuo(9,a)<<endl;
    }
    /*int tmp = kangtuo(9, a);
    cout << tmp << endl;
    reverse_kangtuo(9, 15850, s);
    for (int i = 0; i <= 10; i++)
    {
    cout << s[i];
    }
    cout << endl;
    system("pause");*/
    return 0;
}

猜你喜欢

转载自blog.csdn.net/irish_moonshine/article/details/80978720