Codeforces 906B. Seating of Students(构造+DFS)

  行和列>4的可以直接构造,只要交叉着放就好了,比如1 3 5 2 4和2 4 1 3 5,每一行和下一行用不同的方法就能保证没有邻居。

  其他的可以用爆搜,每次暴力和后面的一个编号交换并判断可行性。

  写dfs的话其实行和列>4的就不用刻意构造了,这个dfs方法可以$O(n*m)$跑出一个构造方案。

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#define ll long long
using namespace std;
const int maxn=500010;
int n, m;
int pos[maxn];
int dx[4]={0, 1, 0, -1}, dy[4]={1, 0, -1, 0};
inline void read(int &k)
{
    int f=1; k=0; char c=getchar();
    while(c<'0' || c>'9') c=='-' && (f=-1), c=getchar();
    while(c<='9' && c>='0') k=k*10+c-'0', c=getchar();
    k*=f;
}
bool check(int i, int j)
{
    int x=(i-1)/m+1, y=(i-1)%m+1, x2=(j-1)/m+1, y2=(j-1)%m+1;
    for(int k=0;k<4;k++) if(x+dx[k]==x2 && y+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()
{
    read(n); read(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)) return puts("NO"), 0;
    puts("YES");
    for(int i=1;i<=n;i++, puts("")) 
    for(int j=1;j<=m;j++) 
    printf("%d ", pos[(i-1)*m+j]);
} 
View Code
原文地址:https://www.cnblogs.com/Sakits/p/8099234.html