行和列>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]); }