2013多校第四场 C题

解题思路:

  首先考虑题目数据大小范围, 总共9个不同数字的全排列, 9! = 3*10^5

  假设N = 9!, 意味着,拼图的状态有N种, 将其看成顶点.[1,N]

  则因为每次只能够移动0, 且每次只能向四个方向移动,则意味着每个顶点至多有四条边.且每条边的

长度为1.

  假定序列 (876543210) 目标序列, 其编号为 st, 则我们可以通过求 

  单源点的最短路. 求出从st出发到其他顶点v的最短距离 dis[v].

  那么对于T次询问操作. 我们只需要O(1)的时间 输出dis[v]就可以了. 

  另外还有个问题就是. 对于 (0,1,..,8)的全排列,如何唯一编号.这里就用到了 康托展开.

  我们其实只要知道结论就可以了.:

    对于一个(1,2,3,..,n)的全排列中的某个排列:  An,An-1,..,A1, 其前面有多少个比它小.(换句话说就是第几个排列)

    假定排列序号为 K,  K = an*(n-1)! + an-1*(n-2)! + ... + a1*0!    ,

    其中 ai 表示 第i位后面有多少个数比 Ai小.

  每次处理排列唯一编号需要时间为 10*10 = 100

  使用BFS层次搜索,从st开始搜索所有节点,时间复杂度为 O(N), 

  总时间复杂度为  O(N*100) =  10^7

  另外, 此题是 八数码问题.  有多种解法.

    1. 因为N不大,可以直接打表然后输出

    2. 使用启发式搜索 A*, IDA*

    3. 其它算法.

View Code
#include <iostream>
#include <vector>
#include <set>
#include <queue>
#include <cstdio>
#include <cstring>

using namespace std;

#define MAXN 400000
struct node
{
    int s[9];
    int t;
};
int mp[MAXN];
int fac[9]= {1,1,2,6,24,120,720,5040,40320};

int change_to_int(int s[])
{
    int t=0;
    int count;
    for(int i=0; i<9; i++)
    {
        count=0;
        for(int j=i+1; j<9; j++)
        {
            if(s[i]>s[j])
                count++;
        }
        t+=count*fac[9-i-1];
    }
    return t+1;
}

node change(node a,int i)
{
    int x;
    for(int j=0; j<9; j++)
    {
        if(a.s[j]==0)
        {
            x=j;
        }
//        if(a.s[j]>=9||a.s[j]<0)
//            printf("error!\n");//useless
    }
    if(i==0)
    {
        if(x<3)
            return a;
        else
        {
            swap(a.s[x],a.s[x-3]);
            return a;
        }
    }
    if(i==1)
    {
        if(x>=6)
            return a;
        else
        {
            swap(a.s[x],a.s[x+3]);
            return a;
        }
    }
    if(i==2)
    {
        if(x==6||x==3||x==0)
        {
            return a;
        }
        else
        {
            swap(a.s[x],a.s[x-1]);
            return a;
        }

    }
    if(i==3)
    {
        if(x==8||x==5||x==2)
            return a;
        else
        {
            swap(a.s[x],a.s[x+1]);
            return a;
        }
    }
}

void BFS()
{
    node a,b;
    int x;
    queue<node> v;
    for(int i=8; i>=0; i--)
        a.s[8-i]=i;
    a.t=1;
    mp[change_to_int(a.s)]=1;
    v.push(a);
    while(!v.empty())
    {
        a=v.front();
        v.pop();
        for(int i=0; i<4; i++)
        {
            b=change(a,i);
            b.t++;
            x=change_to_int(b.s);
            if(mp[x]==0)
            {
                mp[x]=b.t;
                v.push(b);
            }
        }
    }
}

int main()
{
    int n;
    node sd;
    memset(mp,0,sizeof(mp));
    BFS();
    scanf("%d",&n);
    while(n--)
    {
        for(int i=0; i<9; i++)
            scanf("%d",&sd.s[i]);
        int x=change_to_int(sd.s);
        if(mp[x]==0)
            printf("impossible!\n");
        else
            printf("%d\n",mp[x]-1);
    }
}
原文地址:https://www.cnblogs.com/yefeng1627/p/3049538.html