UVA 716 - Commedia dell' arte 逆序数


 Commedia dell' arte 

So called commedia dell' arte is a theater genre firstplayed at Italy in the beginning of the sixteenth century. It was inspiredwith the Roman Theater. The play had no fixed script and the actors (alsocalled performers) had to improvise a lot. There were only a simpledirections by the author like "enter the stage and make something funny" or``everyone comes on stage and everything is resolved happily". You can see itmight be very interesting to play the commedia dell' arte. Thereforethe ACM want to put a new play on a stage, which was completely unknownbefore. The main hero has a puzzle that takes a very important role in theplay and gives an opportunity of many improvisations.


The puzzle is the worldwide known Lloyd's Fifteen Puzzle. ACM wantsto make the play more interesting so they want to replace the``standard" puzzle with a three-dimensional one. The puzzle consistsof a cube containing M3 slots. Each slot except onecontains a cubic tile (one position is free).The tiles are numbered from 1 to M3-1.The goal of the puzzle is to get the original ordering ofthe tiles after they have been randomly reshuffled. The only allowedmoves are sliding a neighbouring tile into the free position along oneof the three principal directions. Original configuration is when slotwith coordinates (x,y,z) from $\{0, \dots ,M-1\}^3$contains tile number z.M2+y.M+x+1 and slot(M-1,M-1,M-1) is free.


Your are to write a program to determine whether it is possible to solve the puzzle or not.

Input 

The input consists of N cases. The first line of the inputcontains only positive integer N. Then follow the cases. Thefirst line of each case contains only one integer M, $1 \leM \le 100$.It is the size of 3D puzzle cube. Then followM lines, each contains exactly M2 numberson the tiles for one layer. First is the layer on the top of the cube andthe last one on the bottom. In each layer numbers are arranged from the lefttop corner linewise to the right bottom corner of the layer. In other words,slot with coordinates (x,y,z) is described by the(x+M.y+1)-th number on the (z+1)-th line.Numbers are separated by space. Number 0 means free position.

Output 

For each case, print exactly one line. If the original configuration can be reached by sliding the tiles,print the sentence `Puzzle can be solved.'. Otherwise, print thesentence `Puzzle is unsolvable.'.

Sample Input 

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

Sample Output 

Puzzle is unsolvable.
Puzzle can be solved.



Miguel A. Revilla
2000-02-15

题意:就是问一个3维的数码问题是否有解。


思路:

我们先简化一下问题,先看下2维情况下是怎么判断有没有解的。我们能通过排列的逆序数的奇偶性和M的奇偶性来判断是否有解,这里的逆序数是(1,2,3....M×M-1)的逆序数,不用把0加进去,而目标状态的逆序数是0,是偶数。当M是奇数的时候,不管怎么移动,逆序数的奇偶性都是不会改变的,自己分类讨论一下。 M是偶数的时候,上下移动会改变奇偶性,但是只要知道目标0和初始0在哪一行就知道奇偶性改变的情况了。回到3维的情况,其实也是差不多的,不要被立体迷惑了,我们把输入的东西当作一个2维的数码来想就行了,不同的只有0移动的方法多了两种而已。 所以这个题目只需要求一下逆序数的奇偶性,然后根据M的奇偶性,以及其实0的y坐标进行讨论就OK了。 这个条件的必要性很显然,但是充分性不大会证....


代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <string.h>
using namespace std;
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define rrep(i,b,a) for(int i = (b); i >= (a); --i)
#define clr(a,x) memset(a,x,sizeof(a))
#define eb emplace_back
const int maxn = 100 * 100 * 100 + 5;
int sum[maxn];

inline int lowbit(int x) { return x & (-x); }

void add(int p,int x)
{
    while (p < maxn) {
        sum[p] += x;
        p += lowbit(p);
    }
}

int query(int l,int r)
{
    if (l > r) return 0;
    int ret = 0; --l;
    while (r >= 1) {
        ret += sum[r];
        r -= lowbit(r);
    }
    while (l >= 1) {
        ret += sum[l];
        l -= lowbit(l);
    }
    return ret;
}

int main()
{
    #ifdef ACM
        freopen("in.txt","r",stdin);
    #endif // ACM
    int T; cin >> T;
    while (T--) {
        int M; scanf("%d",&M);
        clr(sum,0);
        int zero_idx;
        int rev = 0;
        rep(i,0,M*M*M) {
            int d; scanf("%d",&d);
            if (d == 0) zero_idx = i;
            else {
                rev += query(d+1,M*M*M) % 2;
                add(d,1);
                rev &= 1;
            }
        }
        if (~M & 1) {
            int z = zero_idx / (M * M);
            int y = zero_idx % (M * M) / M;
            int x = zero_idx % (M * M) % M;
            if (((M-1) - z) % 2) rev ^= 1;
            if ((M-1-y) % 2) rev ^= 1;
        }
        puts(rev == 0 ? "Puzzle can be solved." : "Puzzle is unsolvable.");
    }
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值