zoukankan      html  css  js  c++  java
  • N*N数码问题

     奇数码问题

    时间限制: 1 Sec  内存限制: 128 MB

    题目描述

    你一定玩过八数码游戏,它实际上是在一个3*3的网格中进行的,1个空格和1~8这8个数字恰好不重不漏地分布在这3*3的网格中。
    例如:
    5 2 8
    1 3 _
    4 6 7
    在游戏过程中,可以把空格与其上、下、左、右四个方向之一的数字交换(如果存在)。
    例如在上例中,空格可与左、上、下面的数字交换,分别变成:
    5 2 8       5 2 _      5 2 8
    1 _ 3       1 3 8      1 3 7
    4 6 7       4 6 7      4 6 _

    奇数码游戏是它的一个扩展,在一个n*n的网格中进行,其中n为奇数,1个空格和1~n*n-1这n*n-1个数恰好不重不漏地分布在n*n的网格中。
    空格移动的规则与八数码游戏相同,实际上,八数码就是一个n=3的奇数码游戏。

    现在给定两个奇数码游戏的局面,请判断是否存在一种移动空格的方式,使得其中一个局面可以变化到另一个局面。

    输入

    多组数据,对于每组数据:
    第1行一个整数n,n<500,n为奇数。
    接下来n行每行n个整数,表示第一个局面。
    接下来n行每行n个整数,表示第二个局面。
    局面中每个整数都是0~n*n-1之一,其中用0代表空格,其余数值与奇数码游戏中的意义相同,保证这些整数的分布不重不漏。

    输出

    对于每组数据,若两个局面可达,输出TAK,否则输出NIE。

    样例输入

    3
    1 2 3
    0 4 6
    7 5 8
    1 2 3
    4 5 6
    7 8 0
    1
    0
    0
    

    样例输出

    TAK
    TAK


    http://www.cnblogs.com/yuyixingkong/archive/2013/09/23/3335667.html

    八数码问题的有解无解的结论:

    一个状态表示成一维的形式,求出除0之外所有数字的逆序数之和,也就是每个数字前面比它大的数字的个数的和,称为这个状态的逆序。

    若两个状态的逆序奇偶性相同,则可相互到达,否则不可相互到达。

    N×N的棋盘,N为奇数时,与八数码问题相同。

    N为偶数时,空格每上下移动一次,奇偶性改变。称空格位置所在的行到目标空格所在的行步数为空格的距离(不计左右距离),若两个状态的可相互到达,则有,两个状态的逆序奇偶性相同且空格距离为偶数,或者,逆序奇偶性不同且空格距离为奇数数。否则不能。

    #include<bits/stdc++.h>
    #define N 252500
    using namespace std;
    int a[255000],b[255000];
    int n;
    
    void updata(int x[],int pos,int v)
    {
        while(pos<=N)
        {
            x[pos]+=v;
            pos+=pos&(-pos);
        }
    }
    int sum(int x[],int pos)
    {
        int ans=0;
        while(pos>0)
        {
            ans+=x[pos];
            pos-=pos&(-pos);
        }
        return ans;
    }
    
    
    long long f(int x[])
    {
        int c[255000];
        long long ans=0;
        for(int i=1; i<=n; i++)
        {
            if(x[i]!=0)
            {
                ans+=sum(c,N)-sum(c,x[i]);
                updata(c,x[i],1);
            }
    
    
        }
        return ans;
    }
    
    
    int main()
    {
        while(scanf("%d",&n)==1)
        {
            n=n*n;
            for(int i=1; i<=n; i++)
                scanf("%d",&a[i]);
            for(int i=1; i<=n; i++)
                scanf("%d",&b[i]);
    
    
            if(f(a)%2==f(b)%2)
                printf("TAK
    ");
            else
                printf("NIE
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    韩式英语
    Daily dictation 听课笔记
    words with same pronunciation
    you will need to restart eclipse for the changes to take effect. would you like to restart now?
    glottal stop(britain fountain mountain)
    education 的发音
    第一次用Matlab 的lamada语句
    SVN的switch命令
    String的split
    SVN模型仓库中的资源从一个地方移动到另一个地方的办法(很久才解决)
  • 原文地址:https://www.cnblogs.com/tian-luo/p/9238195.html
Copyright © 2011-2022 走看看