Seating of Students (dfs模拟+思维)

Seating of Students

Students went into a class to write a test and sat in some way. The teacher thought: "Probably they sat in this order to copy works of each other. I need to rearrange them in such a way that students that were neighbors are not neighbors in a new seating."

The class can be represented as a matrix with n rows and m columns with a student in each cell. Two students are neighbors if cells in which they sit have a common side.

Let's enumerate students from 1 to n·m in order of rows. So a student who initially sits in the cell in row i and column j has a number (i - 1)·m + j. You have to find a matrix with n rows and m columns in which all numbers from 1 to n·m appear exactly once and adjacent numbers in the original matrix are not adjacent in it, or determine that there is no such matrix.


Input

The only line contains two integers n and m (1 ≤ n, m ≤ 105; n·m ≤ 105) — the number of rows and the number of columns in the required matrix.

Output

If there is no such matrix, output "NO" (without quotes).

Otherwise in the first line output "YES" (without quotes), and in the next n lines output m integers which form the required matrix.

Examples
Input
2 4
Output
YES
5 4 7 2 
3 6 1 8 
Input
2 1
Output
NO
Note

In the first test case the matrix initially looks like this:

1 2 3 4
5 6 7 8

It's easy to see that there are no two students that are adjacent in both matrices.

In the second test case there are only two possible seatings and in both of them students with numbers 1 and 2 are neighbors.

这是一道比较有难度的模拟题

题意:给你一个n*m矩阵,里面数字顺序从1-n*m,

1 2 3 4

5 6 7 8……

……

问我们能不能输出一个矩阵使得原有数字都不相邻,可以输出YES并输出满足的矩阵,否则输出NO

思路:根据题目所给的数据范围我们知道肯定不能用二维数组储存数字然后dfs搜索遍历,而是直接进行模拟遍历,题目给了一个公式(i - 1)·m + j。也就是如果我们知道了矩阵中的位置(i,j)那这个位置原始数字应该是(i-1)*m+j,那么反过来如果我们知道了一个数字如果得到这个数字的原始在矩阵中的位置呢如果已知数字大小是i那么这个数字在矩阵的初始位置x = (i-1)/m+1

y = (i-1) % m +1,(x,y)就是初始位置,有了这个我们就不需要用二维数组储存了,直接用一维数组储存就行了。怎么存呢?就是还是用二次循环和储存二维数组一样,只不过把i,j根据公式转成数字存在一维数组中。然后dfs,参数是就是从1-n*m数字,

然后转成(x,y)坐标后我们就也可以得到它的上方和左方的坐标,然后看是否和当前要放的数字相邻(因为我们根据公式算出的坐标都是在原始顺序矩阵中的坐标所以如果坐标相邻说明放上的数字还是相邻的所以不行),为什么只判断上方和左方呢,因为我们是顺序搜索一个一个的放,下方和右方还没有放,所以只判断放好的数字是否相邻就行。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 5e5+10;
int n,m;
int pos[maxn];
int dx[4] = {0,1,0,-1}, dy[4] = {1,0,-1,0};
bool check(int i,int j){
    int x1 = (i - 1) / m + 1;
    int y1 = (i - 1) % m + 1;
    int x2 = (j - 1) / m + 1;
    int y2 = (j - 1) % m + 1;
    for(int k = 0; k < 4; k++){
        if(x1 + dx[k] == x2 && y1 + dy[k] == y2)
            return 1;
    }
    return 0;
}

bool dfs(int i){
    if(i == n * m + 1)
        return 1;
    int x = (i - 1) / m + 1, y = (i - 1) % m + 1;
    for(int j = i; j <= n * m; j++){
        swap(pos[i],pos[j]);
        if(x != 1 && check(pos[i],pos[(x - 2) * m + y]))
            continue;
        if(y != 1 && check(pos[i],pos[(x - 1) * m + y - 1]))
            continue;
        if(dfs(i+1))
            return 1;
        swap(pos[i],pos[j]);
    }
    return 0;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            pos[(i - 1) * m + j] = (i - 1) * m + j;
        }
    }
    if(!dfs(1)){
        puts("NO");
        return 0;
    }
    puts("YES");
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            if(j == 1)
                printf("%d",pos[(i - 1) * m + j]);
            else
                printf(" %d",pos[(i - 1) * m + j]);
        }
        puts("");
    }
    return 0;
}

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页