poj2893 M × N Puzzle

M × N Puzzle
Time Limit: 4000MS Memory Limit: 131072K
Total Submissions: 3332 Accepted: 940

Description

The Eight Puzzle, among other sliding-tile puzzles, is one of the famous problems in artificial intelligence. Along with chess, tic-tac-toe and backgammon, it has been used to study search algorithms.

The Eight Puzzle can be generalized into an M × N Puzzle where at least one of M and N is odd. The puzzle is constructed with MN − 1 sliding tiles with each a number from 1 to MN − 1 on it packed into a M by N frame with one tile missing. For example, with M = 4 and N = 3, a puzzle may look like:

162
403
759
10811

Let's call missing tile 0. The only legal operation is to exchange 0 and the tile with which it shares an edge. The goal of the puzzle is to find a sequence of legal operations that makes it look like:

123
456
789
10110

The following steps solve the puzzle given above.

START

162
403
759
10811

DOWN

102
463
759
10811
LEFT
120
463
759
10811

UP

123
460
759
10811

 

RIGHT

123
406
759
10811

UP

123
456
709
10811
UP
123
456
789
10011

LEFT

123
456
789
10110

GOAL

Given an M × N puzzle, you are to determine whether it can be solved.

Input

The input consists of multiple test cases. Each test case starts with a line containing M and N (2 ≤ MN ≤ 999). This line is followed by M lines containing N numbers each describing an M × N puzzle.

The input ends with a pair of zeroes which should not be processed.

Output

Output one line for each test case containing a single word YES if the puzzle can be solved and NO otherwise.

Sample Input

3 3
1 0 3
4 2 5
7 8 6
4 3
1 2 5
4 6 9
11 8 10
3 7 0
0 0

Sample Output

YES
NO

Source




规律题,正好之前证过规律大概就是整个局面的逆序数+起始0的位置的坐标(x,y)中xy的和+rol+col+rol*col-1的奇偶

稍微证一下,

如果左右移动,那么起始的0的位置和终止0的位置四个坐标值相加一定是奇数,然后移动了逆序数肯定也奇偶变化,所以移动后奇偶值不变

上下移动,0的位置照样和是奇数,然后,取中间一段(0,a,b,c,d,e)变成(e,a,b,c,d,0),那么如果列为奇数,那么0往前移动关于0的逆序对奇偶不变,关于e的奇偶也不变,如果列为偶数,两个都变化总奇偶也不变。

所以,只要保证奇偶不变就能走到,奇偶变了就走不到了

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define MAXN 1000005

struct Tree
{
    int l,r,val;
};

Tree tree[MAXN*5];
int n;

void Build(int t,int l,int r)
{
    tree[t].val=0;
    tree[t].l=l;
    tree[t].r=r;
    if (l==r) return;
    int mid=(l+r)/2;
    Build(2*t+1,l,mid);
    Build(2*t+2,mid+1,r);
}

int Count(int t,int l,int r)
{
    if (tree[t].l==l && tree[t].r==r) return tree[t].val;
    int ret=0;
    int mid=(tree[t].l+tree[t].r)/2;
    if (l<=mid) ret+=Count(2*t+1,l,min(r,mid));
    if (r>mid) ret+=Count(2*t+2,max(l,mid+1),r);
    return ret;
}

void Update(int t,int idx)
{
    int l=tree[t].l;
    int r=tree[t].r;
    if (l==r)
    {
        tree[t].val=1;
        return;
    }
    int mid=(l+r)/2;
    if (idx<=mid) Update(2*t+1,idx);
    else Update(2*t+2,idx);
    tree[t].val=tree[2*t+1].val+tree[2*t+2].val;
}

int main()
{
    int i,j,r,c,x;
    while(1)
    {
        scanf("%d%d",&r,&c);
        if (r==0 && c==0) break;
        n=r*c;
        Build(0,0,n-1);
        long long sum=r+c+n-1;
        for (i=0;i<r;i++)
        {
            for (j=0;j<c;j++)
            {
                scanf("%d",&x);
                if (x==0)
                {
                    sum+=(i+j);
                }
                sum+=Count(0,x,n-1);
              //  printf("%d: %lld\n",x,Count(0,x,n-1));
                Update(0,x);
            }
        }
        if (sum%2==0) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值