AcWing:108. 奇数码问题(归并排序 + 逆序数)

你一定玩过八数码游戏,它实际上是在一个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 _

奇数码游戏是它的一个扩展,在一个nn×nn的网格中进行,其中nn为奇数,1个空格和1~n2−1n2−1这n2−1n2−1个数恰好不重不漏地分布在nn×nn的网格中。

空格移动的规则与八数码游戏相同,实际上,八数码就是一个n=3n=3的奇数码游戏。

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

输入格式

多组数据,对于每组数据:

第1行输入一个整数nn,nn为奇数。

接下来nn行每行nn个整数,表示第一个局面。

再接下来nn行每行nn个整数,表示第二个局面。

局面中每个整数都是00~n2−1n2−1之一,其中用00代表空格,其余数值与奇数码游戏中的意义相同,保证这些整数的分布不重不漏。

输出格式

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

数据范围

1≤n<5001≤n<500

输入样例:

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

输出样例:

TAK
TAK

算法:归并排序 + 逆序数

题解:将两个二维数组转换为一维数组(其中不包含0,0为空格),计算出两个一维数组的逆序数,然后算出它们的奇偶性是否相同,相同则可以变化成另一个局面,否则不能。

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

const int maxn = 3e5+7;

typedef long long ll;

int arr[maxn];
int b[maxn];
ll cnt;

void merge_sort(int l, int mid, int r) {
    int i = l, j = mid + 1;
    int k = 0;
    while(i <= mid || j <= r) {
        if(j > r || (i <= mid && arr[i] <= arr[j])) {
            b[k++] = arr[i++];
        } else {
            cnt += mid - i + 1;
            b[k++] = arr[j++];
        }
    }
    for(int i = 0; i < k; i++) {
        arr[l + i] = b[i];
    }
}

void merge(int l, int r) {
    if(l < r) {
        int mid = (l + r) >> 1;
        merge(l, mid);
        merge(mid + 1, r);
        merge_sort(l, mid, r);
    }
}

void fun(ll &sum, int n) {
    int k = 0;
    for(int i = 1; i <= n * n; i++) {
        int x;
        scanf("%d", &x);
        if(x != 0) {
            arr[++k] = x;
        }
    }
    cnt = 0;
    merge(1, k);
    sum = cnt;
}

int main() {
    int n;
    while(~scanf("%d", &n)) {
        ll sum1, sum2;
        fun(sum1, n);
        fun(sum2, n);
        if((long long)abs(sum1 - sum2) % 2) {
            printf("NIE\n");
        } else {
            printf("TAK\n");
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/buhuiflydepig/p/11296120.html

时间: 2024-08-05 10:46:09

AcWing:108. 奇数码问题(归并排序 + 逆序数)的相关文章

Inversion(HDU_4911) 归并排序+逆序数对

Inversion Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 3171    Accepted Submission(s): 1154 Problem Description bobo has a sequence a1,a2,-,an. He is allowed to swap two adjacent numbers f

数据结构 归并排序-逆序数对

逆序对是指数列a[1],a[2],a[3]-中的任意两个数a[i],a[j] (i<j),如果a[i]>a[j],那么我们就说这两个数构成了一个逆序对. 而归并排序的合并两个排列的过程中 会将右边的有序序列的元素依次插入前面的 有序序列 如(3 7 12)   ( 5 6 8) 将5 插入  (3 7 12) 中 因为后面有序 所以 假设   5和左边全部元素构成逆序对  所以有mid+1 而左边序列又有start1 个数比5 小  所以 逆序数就是  mid+1-start1 这样就能大大缩

Frosh Week(HDU_3743)归并排序+逆序数对

Frosh Week Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2772    Accepted Submission(s): 923 Problem Description During Frosh Week, students play various fun games to get to know each other a

归并排序(逆序数问题)详解

微信公众号:bigsai 前言 在排序中,我们可能大部分更熟悉冒泡排序.快排之类.对归并排序可能比较陌生.然而事实上归并排序也是一种稳定的排序,时间复杂度为O(nlogn). 归并排序是基于分治进行归并的,有二路归并和多路归并.我们这里只讲二路归并并且日常用的基本是二路归并.并且归并排序的实现方式有递归形式和非递归形式.要注意其中的区分(思想上没有大的区别,只是划分上会有区分后面会对比). 并且归并排序很重要的一个应用是求序列中的逆序数个数.当然逆序数也可以用树状数组完成,这里就不介绍了. 归并

AcWing 107. 超快速排序(归并排序 + 逆序对)

在这个问题中,您必须分析特定的排序算法----超快速排序. 该算法通过交换两个相邻的序列元素来处理n个不同整数的序列,直到序列按升序排序. 对于输入序列9 1 0 5 4,超快速排序生成输出0 1 4 5 9. 您的任务是确定超快速排序需要执行多少交换操作才能对给定的输入序列进行排序. 输入格式 输入包括一些测试用例. 每个测试用例的第一行输入整数n,代表该用例中输入序列的长度. 接下来n行每行输入一个整数aiai,代表用例中输入序列的具体数据,第i行的数据代表序列中第i个数. 当输入用例中包含

奇数码问题(逆序对求解)

两个矩阵,排成线性序列,若逆序对奇偶性相同,则可以互相转化矩阵 注意:0不算入内, #include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const ll nil=20000000000; const int maxn=500000+10; ll L[maxn/2],R[maxn/2]; int n; ll a[maxn]; in

归并排序 逆序数

很好理解: int n,a[500010],c[500010]; long long ans; void msort(int L,int R) { if(L==R)return ; int mid=(L+R)>>1; msort(L,mid); msort(mid+1,R); int i=L,k=L,j=mid+1; while(i<=mid&&j<=R) if(a[i]<=a[j]) c[k++]=a[i++]; else c[k++]=a[j++],ans

求逆序数

第一部分:题目 描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 现在,给你一个N个元素的序列,请你判断出它的逆序数是多少. 比如 1 3 2 的逆序数就是1. 输入 第一行输入一个整数T表示测试数据的组数(1<=T<=5)每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=1000000)随后的一行共有N个整数Ai(0<=Ai<1000000000),表示数列中的所

CH Round #72 奇数码问题[逆序对 观察]

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