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;
}

以下是一个简单的购票系统模拟的Go语言实现: ```go package main import ( "fmt" "sync" ) // Ticket represents a ticket for a specific seat type Ticket struct { seatNumber int isSold bool } // SeatMap represents the seating arrangement for the event type SeatMap struct { tickets []*Ticket mutex sync.Mutex } // NewSeatMap creates a new seat map with n tickets func NewSeatMap(n int) *SeatMap { tickets := make([]*Ticket, n) for i := 0; i < n; i++ { tickets[i] = &Ticket{seatNumber: i + 1} } return &SeatMap{tickets: tickets} } // SellTicket sells a ticket for a specific seat func (s *SeatMap) SellTicket(seatNumber int) error { s.mutex.Lock() defer s.mutex.Unlock() if seatNumber < 1 || seatNumber > len(s.tickets) { return fmt.Errorf("invalid seat number") } ticket := s.tickets[seatNumber-1] if ticket.isSold { return fmt.Errorf("ticket already sold") } ticket.isSold = true return nil } // AvailableSeats returns the number of available seats func (s *SeatMap) AvailableSeats() int { s.mutex.Lock() defer s.mutex.Unlock() count := 0 for _, ticket := range s.tickets { if !ticket.isSold { count++ } } return count } func main() { seatMap := NewSeatMap(10) // Sell a ticket for seat 3 err := seatMap.SellTicket(3) if err != nil { fmt.Println(err) } // Sell a ticket for seat 3 again (should fail) err = seatMap.SellTicket(3) if err != nil { fmt.Println(err) } // Sell a ticket for an invalid seat number (should fail) err = seatMap.SellTicket(11) if err != nil { fmt.Println(err) } // Print the number of available seats (should be 8) fmt.Println(seatMap.AvailableSeats()) } ``` 该代码实现了一个简单的购票系统模拟,包括创建座位地图、出售票、检查可用座位等功能。SeatMap 结构体包含一个 Ticket 切片,每个 Ticket 包含座位编号和是否已售出的标志。SellTicket 方法使用互斥锁保证线程安全性,并检查座位号是否有效以及座位是否已售出。AvailableSeats 方法同样使用互斥锁保证线程安全性,并统计未售出的座位数量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值