传送门:http://codeforces.com/contest/907/D
题意:给一个n行m列的矩阵,原矩阵按数字顺序从第一行开始向后填充,寻找一种方案使得原矩阵中相邻的数字在新矩阵中都不相邻。
思路:随机大法好啊~学习一下随机算法。
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
vector <int> a[N],b[N];
vector <int> T[N];
int jx[]={0,0,1,-1};
int jy[]={1,-1,0,0};
bool flag[N];
int n,m;
int rand_()
{
return rand()*rand()%(n*m)+1;
}
bool check(int o,int x,int y)
{
if(x<=0 || y<=0) return false;
for (int i=0;i<T[o].size();i++){
if(T[o][i]==b[x][y]) return true;
}
return false;
}
void init()
{
srand(1);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
a[i].resize(m+5);
b[i].resize(m+5);
for(int j=1;j<=m;j++){
a[i][j]=(i-1)*m+j;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=0;k<4;k++){
int fx=i+jx[k];
int fy=j+jy[k];
if(fx>=1 && fy>=1 && fx<=n && fy<=m) T[a[i][j]].push_back(a[fx][fy]);
}
}
}
}
void solve ()
{
int num;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
num=0;
int r=rand_();
while ((num <=(n*m)*2 )&& (flag[r]==false || check(r,i-1,j) || check(r,i,j-1))){
r=rand_();
num++;
}
if(num > (n*m)*2) return;
flag[r]=false;
b[i][j]=r;
}
}
printf("YES\n");
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
printf("%d ",b[i][j]);
printf("\n");
}
exit(0);
}
int main ()
{
//yyy_3y
init();
// printf("1\n");
for(int i=1;i<=100;i++){
memset(flag,true,sizeof(flag));
solve();
}
printf("NO\n");
return 0;
}