洛谷 P6291 [eJOI2017]骆驼 / HHHOJ #247. 「NOIP模拟赛 叁」骆驼 题解--zhengjun
思路
一看就是构造题,显然要分成若干块 \(5\times5\) 的小块,然后发现对于一个小块中,只有最中间的那格可以从别的小块中一步跳进来。
然后我们打一个爆搜,打出从当前小块的中间走到各个方向相邻的小块的方案。
这样就可以在小块间移动了。
由于我们需要把所有的点都绕一遍,那么显然是在 \(2\sim \frac{N}{5}\) 行上边绕来绕去,直到最后一列绕完之后从第一行绕回第一格。
所以在 \(N\) 为奇数的时候,最后上去的时候需要把两列一起处理掉,然后就爆搜跑一个 \(5\times10\) 绕一遍的解(从 \((3,3)\) 开始走最后走到 \((3,1)\)),然后输出即可,注意特判 \(N=5\) 和 \(N=15\) 的点。
代码
#include<bits/stdc++.h>
using namespace std;
int n;
int st[11][11]={
{ 1,13,16, 0,12},
{ 9, 4,23,20, 7},
{15,18,11,14,17},
{ 2,21, 8, 3,22},
{10, 5,24,19, 6},
};
int ed[11][11]={
{21,15, 5,20,14},
{10,18,23,11, 3},
{25, 7, 1,16, 6},
{22,12, 4,19,13},
{ 9,17,24, 8, 2},
};
int corner[11][11]={
{28,41,50,27,42,18,24, 5,17,10},
{38,21,30,39,13,46,32,12,45, 7},
{49,35, 1,19,34,26,43, 9,25, 4},
{29,40,14,22,31,15,23, 6,16,11},
{37,20,48,36, 2,47,33, 3,44, 8},
};
int down[11][11]={
{18,13, 5,19,14},
{10,21,16,11, 3},
{24, 7, 1,23, 6},
{17,12, 4,20,15},
{ 9,22,25, 8, 2},
};
int r[11][11]={
{10,16, 5,11,17},
{21,13, 8,20, 3},
{ 6,24, 1,15,25},
{ 9,19, 4,12,18},
{22,14, 7,23, 2},
};
int up[11][11]={
{18,10,25,17,11},
{ 5,21,13, 8, 3},
{24,16, 1,23,15},
{19, 9, 4,20,12},
{ 6,22,14, 7, 2},
};
int l[11][11]={
{21,15, 5,20,14},
{10,18,23,11, 3},
{25, 7, 1,16, 6},
{22,12, 4,19,13},
{ 9,17,24, 8, 2},
};
int tmp[11][11]={
{19,45,40,18,46,41,15, 5,30,10},
{38,22,48,43,13,26,32,12,27, 7},
{50,35, 1,24,34,17,29, 9,16, 4},
{20,44,39,21,47,42,14, 6,31,11},
{37,23,49,36, 2,25,33, 3,28, 8},
};
int ans[5001][5001];
void copy(int x,int y,const int (*a)[11],int n,int m,int st){
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)ans[(x-1)*5+i][(y-1)*5+j]=a[i-1][j-1]+st-1;
}
int main(){
cin>>n;
if(n%10==0){
copy(1,1,st,5,5,1);ans[1][4]=n*n;
int m=n/5,now=25;
for(int i=1;i<=m;i++){
if(i&1){
for(int j=2;j<m;j++)copy(j,i,down,5,5,now),now+=25;
copy(m,i,r,5,5,now);now+=25;
}
else if(i!=m){
for(int j=m;j>2;j--)copy(j,i,up,5,5,now),now+=25;
copy(2,i,r,5,5,now);now+=25;
}
else{
for(int j=m;j>1;j--)copy(j,i,up,5,5,now),now+=25;
}
}
for(int i=m;i>2;i--)copy(1,i,l,5,5,now),now+=25;
copy(1,2,ed,5,5,now);now+=25;
}
else if(n==5){
puts("1 14 7 4 15\n\
9 22 17 12 23\n\
19 5 25 20 6\n\
2 13 8 3 16\n\
10 21 18 11 24");
return 0;
}
else{
copy(1,1,st,5,5,1);ans[1][4]=n*n;
int m=n/5,now=25;
for(int i=1;i<m-1;i++){
if(i&1){
for(int j=2;j<m;j++)copy(j,i,down,5,5,now),now+=25;
copy(m,i,r,5,5,now);now+=25;
}
else if(i!=m){
for(int j=m;j>2;j--)copy(j,i,up,5,5,now),now+=25;
copy(2,i,r,5,5,now);now+=25;
}
else{
for(int j=m;j>1;j--)copy(j,i,up,5,5,now),now+=25;
}
}
for(int i=m;i>=2;i--)copy(i,m-1,corner,5,10,now),now+=50;
copy(1,m-1,tmp,5,10,now),now+=50;
for(int i=m-2;i>2;i--)copy(1,i,l,5,5,now),now+=25;
if(m>3)copy(1,2,ed,5,5,now);now+=25;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
printf("%d%c",ans[i][j],"\n "[j<n]);
}
}
return 0;
}