• 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);
        }
    }
  • 相关阅读:
    你的服务器和网站为什么会被反复入侵
    MAC 查看当前安装的JDK位置
    Jmeter高并发测试
    解密AndroidManifest.xml、AXMLPrinter2.jar源码下载
    Win10家庭版如何启用本地组策略
    SQLFlow使用中的注意事项--设置篇
    Sqlflow 之隐私政策(Privacy plolicy)介绍
    血缘关系分析工具SQLFLOW--实践指南
    Oracle SQL 性能优化利器
    SQLFlow数据流分析工具的job功能介绍
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/3049538.html
Copyright © 2020-2023  润新知