M × N Puzzle - 逆序对【N*M数码问题局面之间可达性判定】

M × N Puzzle

Sol:

\(N*M\)数码某局面到达另一局面的可行性判定

可以通过逆序对个数的奇偶性是否相同来判定。

我们将这\(N*M-1\)个数写成一列来看。

  • 考虑行为奇数,列为奇数的情况->逆序对个数奇偶性相同时可达

    空格左右移动不会改变逆序对的个数,而上下移动相当于改变了该列前后共\(M-1\)个数的逆序对个数,由于\(M-1\)是偶数,所以移动前后逆序对个数奇偶性不变。

  • 考虑行为奇数,列为偶数的情况->(逆序对个数+前后状态空格行数之差)奇偶性相同时可达

    上下移动会改变共\(M-1\)个数的逆序对个数,而\(M-1\)是奇数,当上下移动了偶数行时,奇偶性不变;上下移动了奇数行时,奇偶性改变。

  • 行为偶数时,同上。

    AC CODE:

Source Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read(){
    int x=0,f=1;char ch=‘ ‘;
    while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch<=‘9‘&&ch>=‘0‘){x=(x<<3)+(x<<1)+(ch^‘0‘);ch=getchar();}
    return x*f;
}
const int N = 1000 + 2;
int n,m;
int a[N*N],tot;
int tr[N*N];
int lowbit(int x){
    return x&-x;
}
void modify(int p,int k){
    for(int i=p;i<=tot;i+=lowbit(i)){
        tr[i]+=k;
    }
}
int query(int p){
    int ans=0;
    for(int i=p;i;i-=lowbit(i)){
        ans+=tr[i];
    }
    return ans;
}
int main(){
//  freopen("data.in","r",stdin);
//  freopen("sol.out","w",stdout);
    while(1){
        n=read();m=read();
        if(!n&&!m) break;
        memset(tr,0,sizeof(tr));
        tot=0;int pos;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                int x;x=read();
                if(x) a[++tot]=x;
                else pos=i;
            }
        }
        int mul=n*m;
        int ans=0;
        for(int i=tot;i;i--){
            ans+=query(a[i]-1);
            modify(a[i],1);
        }
        if(m%2==0){
            ans+=n-pos;
        }
        if(ans%2==0) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Loi-Brilliant/p/9785056.html

时间: 2024-10-10 02:56:53

M × N Puzzle - 逆序对【N*M数码问题局面之间可达性判定】的相关文章

hdu多校第四场 1007 (hdu6620) Just an Old Puzzle 逆序对

题意: 给你一个数字拼图,问你数字拼图能否能复原成原来的样子. 题解: 数字拼图的性质是,逆序数奇偶相同时,可以互相转化,逆序数奇偶不同,不能互相转化. 因此统计逆序对即可. #include<iostream> using namespace std; int main(){ int t; scanf("%d",&t); while(t--){ int a[20]; int kg; for(int i=1;i<=16;i++){ scanf("%d

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 _ 奇数码游戏是它的一个扩展,

【练习——逆序对】N*M Puzzle / Simple Puzzle

HDU P3600 Simple Puzzle POJ P2893 N*M Puzzle (咕在前面, 这是两道基本一样的题, 我都没有A掉, 但我觉得我写的十分正确!!!不想改了先放上来orz 思路:这个题真是妙啊qwq我特意新建了一个“妙啊”分类给它qwq(然而A不掉 将二维转化为一维, 从左往右从上至下, 遇到0(空格)跳之~ 可知空格左右移动对一维序列无影响, 上下移动会向前或向后移动, 跳过(m-1)个格子//这里n行m列 如果列数为奇数, (m-1)为偶数, 则无论移动的数与跳过的数

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

两个矩阵,排成线性序列,若逆序对奇偶性相同,则可以互相转化矩阵 注意: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

codeforces 414C C. Mashmokh and Reverse Operation(归并排序求逆序对)

题目链接: C. Mashmokh and Reverse Operation time limit per test 4 seconds memory limit per test 512 megabytes input standard input output standard output Mashmokh's boss, Bimokh, didn't like Mashmokh. So he fired him. Mashmokh decided to go to university

求逆序对(线段树版)

一个序列a1,a2,a3...aN,求出满足:ai > aj 且 i < j 的个数. 一个最容易想到的方法就是枚举所有的i,j看看是否满足,显然是O(n^2)的复杂度.不够好. 可以这样考虑,开一个数组保存这n个数出现的位置和对应的次数,这个数组要开到a数组里最大的那个数MAX,也就是hash,初始状态数组里没有元素,每个数对应的个数都是0. 如果考虑第i个数,找到比它大的所有的数 的个数,查找的范围即 ai+1~MAX,这就是到i这个位置的逆序对的总和,接着把a[i]这个数添加到数组里,也

剑指offer: 数组中的逆序对

1. 最简单的思路,对每个值,遍历与其逆序的数组对:但时间复杂度太高: 2. 归并排序的思路: 先将数组分隔成子数组,先统计出子数组内的逆序对的数目,然后统计两个相邻子数组之间的逆序对的数目: int InversePairsCore(int *data, int * copy, int start, int end) { //递归介绍条件,只剩一个元素 if(start==end) { copy[start]=data[start]; return 0; } int length=(end-s

[HAOI2009]逆序对数列

题目描述 对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数.若对于任意一个由1~n自然数组成的数列,可以很容易求出有多少个逆序对数.那么逆序对数为k的这样自然数数列到底有多少个? 输入输出格式 输入格式: 第一行为两个整数n,k. 输出格式: 写入一个整数,表示符合条件的数列个数,由于这个数可能很大,你只需输出该数对10000求余数后的结果. 输入输出样例 输入样例#1: 4 1 输出样例#1: 3 说明 样例说明: 下列3个数列逆序对数都为1:分别是1 2

bzoj3295动态逆序对

Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 5362  Solved: 1814[Submit][Status][Discuss] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数