奇数码问题

奇数码问题

有一个\(n\times n\)的网格图,网格由\(0\sim n-1\)组成,现在你可以进行操作,每次操作选择0与其相邻的位置上的数交换位置,给出两个网格图的初始局面,询问这两个局面是否能够互相到达,\(n\in\text{奇数},1\leq n\leq 500\)。

此题套结论即可,但是不清楚结论,可以参考我的八数码的总结,但是我至今没有它的完整的证明,网上有一篇,但是我看不懂。

因为n是奇数,于是能够互相到达,当且仅当网格图拆行成列后形成的序列的不考虑0的逆序对个数奇偶性相同,注意这个结论\(n=1\)时候不成立,需要特判。

参考代码:

#include <iostream>
#include <cstdio>
#define il inline
#define ri register
#define ll long long
using namespace std;
ll lxd(int,int,int[]);
int a[250050],b[250050],at,bt,
    te[250050];
int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        at^=at,bt^=bt;
        for(int i(1),j,k;i<=n;++i)
            for(j=1;j<=n;++j){
                scanf("%d",&k);
                if(k)a[++at]=k;
            }
        for(int i(1),j,k;i<=n;++i)
            for(j=1;j<=n;++j){
                scanf("%d",&k);
                if(k)b[++bt]=k;
            }
        if(n==1){puts(a[1]==b[1]?"TAK":"NIE");continue;}
        puts((lxd(1,at,a)&1)==(lxd(1,bt,b)&1)?"TAK":"NIE");
    }
    return 0;
}
ll lxd(int l,int r,int a[]){
    if(l==r)return 0;
    int mid(l+r>>1),i(l),j(mid+1),k(l);
    ll ans(lxd(l,mid,a)+lxd(j,r,a));
    while(i<=mid&&j<=r)
        if(a[i]<=a[j])te[k++]=a[i++];
        else te[k++]=a[j++],ans+=mid-i+1;
    while(i<=mid)te[k++]=a[i++];
    while(j<=r)te[k++]=a[j++];
    for(i=l;i<=r;++i)a[i]=te[i];
    return ans;
}

原文地址:https://www.cnblogs.com/a1b3c7d9/p/11214075.html

时间: 2024-10-12 10:02:49

奇数码问题的相关文章

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

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

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

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

学习笔记(5)

1.在cp拷贝所有文件的时候要注意* 号不能匹配路径汇总的隐藏文件 2.tailf 类似于tail -f,当文件不增长时并不访问文件 3.token(uid,gid,groups)重新获取重新登录 4.chown wang f1 修改f1文件的所有者 5.chgrp rpc f1  修改f1文件的所属组 6.groupmems -a wang -g p1  为p1组添加用户wang usermod -aG g2 wang    将wang用户添加至组g2 gpasswd -a  mage g1

算法竞赛进阶指南做题记录

基本算法 递归与递推 费解的开关 Strange Towers of Hanoi Sumdiv Fractal Streets 前缀和与差分 激光炸弹 IncDec Sequence Tallest Cow 二分 Best Cow Fences 排序 Cinema 货舱选址 七夕祭 Running Median 第K大数 Ultra-QuickSort 奇数码问题 原文地址:https://www.cnblogs.com/Maktub-blog/p/11009723.html

夜深人静写题解--杭电第四场

1001.AND Minimum Spanning Tree 题意:已知一个完全图,共有N个点,按1-N编号,点与点之间的边权为两点的编号相与,求权值和最小生成树,相同权值和输出最小的字典序方案 思路:为了保证可以得到权值和最小,对于每个点可以贪心的去找与其与值最小的点,为保证字典序最小,应找到第一个与其相与可以得到最小的点 方案:枚举每个点二进制位上最低0的位置,得到相遇的点,比如X的二进制位1110011110111,则与其相与的最小的点为1000,若用此方法找到的值比N值大,则将其与1相与

2019 HDOJ Multi-University Training Contest Stage 4(杭电多校)

很抱歉过了这么多天才补这场,最近真的挺忙的…… 出题人是朝鲜的(目测是金策工业?),挺难. 题目链接:http://acm.hdu.edu.cn/contests/contest_show.php?cid=851 A: 签到题. 对于当前的点,若其编号为偶数,则可与1相连使得边权贡献为0.否则从低位向高位找当前点编号的二进制表示的第一个0,使这个0变为1,其他位置变为0并检查新的数字是否小于等于n.若小于等于n则贡献为0,反之贡献为1. 1 /* basic header */ 2 #inclu

10.27--11.3 一周刷题记录

exgcd 贝祖定理推广 贝祖定理可以推广到n个,n>=2 ax+by+cz+...=k if(k%gcd(a,b,c,...)==0) 该式子有整数解 else 没有整数解 Forsaken喜欢数论 因为空间限制,直接省略掉sum数组 记得sum 开long long! int n; const int N=3e7+10; int v[N],p[N],tot_p; long long sum; inline void shai(){ rep(i,2,n){ if(v[i]==0){ v[i]=

【转】八数码问题及A*算法

一.八数码问题八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个空格,与空格相邻的棋子可以移到空格中.要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤.所谓问题的一个状态就是棋子在棋盘上的一种摆法.棋子移动后,状态就会发生改变.解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态.八数码问题一般使用搜索法来解.搜索法有广度优先搜索法.深度优