题目链接:A - Seating of Students
思路:这个题按道理说是搜索。。。但是,我太菜了不会。。。 T_T(求大佬指点
好吧。。。说重点:我们看到数据不能用二维数组来存,只好用一维数组来存了(简单嘛)
然后我们发现,对于2 * 4 来说,
1 2 3 4 我们可以先 5 2 7 4
5 6 7 8 1 6 3 8 ( 这样每一行的两个元素就都不同了
然后再处理列。。
我们发现如果第一行(实际上就是奇数行。。。)所有元素右移(或者左移)一次的话,是不行的。移动两次是可以的
即 7 4 5 2
1 6 3 8 处理完之后就可以保证现在相邻的两个元素之前肯定不相邻了!!!
类比到对于多行多列
我们首先将奇数列的每一个元素上移一位(最后一行由第一行补上),偶数列不变。这样就可以保证每一行中两个元素之前都不相邻!
然后,我们再将所有奇数行右移两个单位,偶数行不变!待处理完之后就是数据大的时候的答案
那么什么是数据小呢?(取 n < m (n>m同理
我们可以通过观察发现对于 n == 1 m <= 3 且 m != 1 和 n == 2 m <= 3 时 显然是不可以的
对于 m > 4 我们可以通过从小到大先输出奇数,再输出偶数得到解
对于 1 * 1 和 3 * 3 要进行特判一下!
1 * 1 时 只有一个元素输出即可
3 * 3 时按照上述的证明方式不存在的,但是实际上是存在的
3 * 3 时 6 1 8
7 5 3
2 9 4 ( 这个矩阵时可以的!!!WA了这个点上了!
对于 n > m 类似方法即可!
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int a[100005];
int b[100005];
int f1[100005];
int f2[100005];
int n,m;
bool flag = 0;
int main()
{
scanf("%d%d",&n,&m);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(f1,0,sizeof(f1));
memset(f2,0,sizeof(f2));
for(int i=1; i<=n*m; i++)
a[i] = b[i] = i;
if(n == 1 && m == 1)
printf("YES\n1\n");
else if(n == 3 && m == 3)
{
printf("YES\n");
printf("6 1 8\n7 5 3\n2 9 4\n");
}
else if(n <= 3 && m <3 || m <= 3 && n < 3)
{
printf("NO\n");
}
else if(n == 1 && m > 3)
{
if(m == 4)
{
printf("YES\n");
printf("3 1 4 2\n");
}
else
{
printf("YES\n");
for(int i=1; i<=m; i+=2)
printf("%d ",a[i]);
for(int i=2; i<=m; i+=2)
printf("%d ",a[i]);
printf("\n");
}
}
else if(m == 1 && n > 3)
{
if(n == 4)
{
printf("YES\n");
printf("3\n1\n4\n2\n");
}
else
{
printf("YES\n");
for(int i=1; i<=n; i+=2)
printf("%d\n",a[i]);
for(int i=2; i<=n; i+=2)
printf("%d\n",a[i]);
printf("\n");
}
}
else if(n <= m)
{
for(int i=1; i<=m*n-m; i+=2)
{
if((i-2)%m == 0)
i--;
a[i] = a[i+m];
}
int p = 1;
for(int i=n*m-m+1; i<=n*m; i+=2)
{
a[i] = b[p];
p += 2;
}
for(int i=1; i<n; i+=2)
{
int f1 = a[(i+1)*m-1];
int f2 = a[(i+1)*m];
for(int j=(i+1)*m; j>=i*m+1; j--)
{
a[j] = a[j-2];
}
a[i*m+1] = f1;
a[i*m+2] = f2;
}
printf("YES\n");
for(int j = 1; j<=n*m; j++)
{
if((j-1)%m==0&&j!=1)
printf("\n");
printf("%d ",a[j]);
}
printf("\n");
}
else if(n > m)
{
for(int i=0; i<n; i+=2)
{
int f1 = a[(i+1)*m];
for(int j = (i+1)*m;j >= i*m+2;j--)
{
a[j] = a[j-1];
}
a[i*m+1] = f1;
}
int p = 0;
for(int i = 1;i<=m;i+=2)
f1[++p] = a[i];
p = 0;
for(int i = m+1;i<=2*m;i+=2)
f2[++p] = a[i];
for(int i=1;i<=n*m-2*m;i+=2)
{
a[i] = a[i+2*m];
if(m % 2 == 1 && (i)%m == 0)
i--;
}
p = 0;
for(int i=n*m-2*m+1;i<=n*m-m;i+=2)
{
a[i] = f1[++p];
}
p = 0;
for(int i=n*m-m+1;i<=n*m;i+=2)
{
a[i] = f2[++p];
}
printf("YES\n");
for(int i=1;i<=n*m;i++)
{
if((i-1)%m == 0&& i != 1)
printf("\n");
printf("%d ",a[i]);
}
printf("\n");
}
return 0;
}
好吧,其实还有一种思路:将 1 到 n*m 中的奇数和偶数分别找出来!
比如 1 2 3 4 --> 1 3 5 7 或者 3 1 4 2 奇数行前 m/2 列是奇数 后 m / 2 列是偶数
5 6 7 8 --> 8 6 4 2 6 8 5 7 偶数行前 m/2 列是偶数 后 m/2 列是奇数
这种方法实现起来应该要比上面的方法代码量要小很多!!!
可以参考这篇博客