六边形
题目描述:
棋盘是由许多个六边形构成的,共有5种不同的六边形编号为1到5,棋盘的生成规则如下:
- 从中心的一个六边形开始,逆时针向外生成一个个六边形。
- 对于刚生成的一个六边形,我们要确定它的种类,它的种类必须满足与已生成的相邻的六边形不同。
- 如果有多个种类可以选,我们选择出现次数最少的种类。
- 情况3下还有多个种类可以选,我们选择数字编号最小的。
现在要你求第\(N\)个生成的六边形的编号?前14个六边形生成图如下:
输入格式:
第一行:\(T\),表示数据组数
接下来\(T\)行,每行一个数:\(N\),表示第\(N\)个六边形
输出格式:
共\(T\)行,每行一个数,表示第\(N\)个数据的答案
样例输入:
4
1
4
10
100
样例输出:
1
4
5
5
数据范围:
100%数据满足
\(1<=T<=20\)
\(1<=N<=10000\)
30%数据满足
\(1<=N<=100\)
时间限制:
0.1S
空间限制:
256M
提示:
remove!!!
题解
emmm,典型的大模拟题。
大模拟题其实就是考码量的,根据题意模拟就行了。
重点是如何模拟六边形,我们平时用的二维数组,其实可以看成是四边形,
那么六边形嘛,其实也可以放在二维数组里面,不一定要把数组填满。
注意数组不要开的太大,博主第一次因为数组开的太大而MLE了。
有些奆佬好像使用倾斜的坐标系可以把二维数组填满,但我这里用的是比较菜的方法。
我们用\((x,y)\)表示当前节点的坐标。
那么它的上方节点就是\((x,y+2)\)(如果是\((x,y+1)\)的话侧面的两个节点是存不下的)
下方节点:\((x,y-2)\)
左上方节点:\((x-1,y+1)\)
左下方节点:\((x-1,y-1)\)
右上方节点:\((x+1,y+1)\)
右下方节点:\((x+1,y-1)\)
记得第一个数不要放在\((1,1)\)或者\((0,0)\)这种角落,最好是数组的最中间,不然会很happy。
那么接下来就是模拟了,因为依次循环模拟增加一个点会很麻烦,需要再记录当前要增加节点应该往哪个方向,圈数增加时还要特判,所以我就每次增加一圈,只要记录当前是第几圈就好了,但是要注意增加时如果达到目标要及时退出,或者把数组开大一点,因为到后面一圈增加的点数会很多。
题目里要求填出现次数最少,编号最小,没有在相邻节点出现的数。
我们根据出现次数最少,编号最小的优先级给5个点排个序。
当选择一个点的时候,这个点的出现次数增加1,那么5个点的排序只会让增加的点往后移动若干位,其他点相对之间的位置是不变的,所以增加点的时候维护一下优先级。(其实只有5个点,增加的时候暴搜应该也可以)
是否在相邻节点出现的话在增加节点的时候判断就好了。
博主由于想节约时间(其实是不想把数组清空的强迫症),在这里使用离线的方法做的。
上代码:
#include<bits/stdc++.h>
using namespace std;
int t,n[29],mx;
int a[10009],l;
int s[5009][5009];//看一下数组里存点的空间,可以发现是按照网格状存储的,所以也可以开小一点
int x=2500,y=2500,tt=1;
struct aa{
int x,s;
}p[9];
bool pd(int x,int y,int xx){
if(s[x-1][y-1]==xx) return 1;
if(s[x-1][y+1]==xx) return 1;
if(s[x+1][y-1]==xx) return 1;
if(s[x+1][y+1]==xx) return 1;
if(s[x][y+2]==xx) return 1;
if(s[x][y-2]==xx) return 1;
return 0;
}
int main(){
scanf("%d",&t);
for(int j=1;j<=t;j++){
scanf("%d",&n[j]);
mx=max(mx,n[j]);
}
int u=1;
a[1]=1;
for(int j=1;j<5;j++)
p[j].x=j+1;
p[5].x=1;p[5].s=1;
s[x][y]=1;
while(1){
for(int j=1;j<=6;j++){
for(int i=1;i<=tt;i++){
if(j==1){
if(i==1){x++;y++;}
else y+=2;
}else if(j==2){x--;y++;}
else if(j==3){x--;y--;}
else if(j==4){y-=2;}
else if(j==5){x++;y--;}
else if(j==6){x++;y++;}
int as=1;
while(pd(x,y,p[as].x)) as++;
p[as].s++;
a[++u]=s[x][y]=p[as].x;
if(u>=mx) break;
int j=as+1;
aa t=p[as];
while(j<=5 && (p[j].s<t.s || (p[j].s==t.s && p[j].x<t.x))){
p[j-1]=p[j];
j++;
}
p[j-1]=t;
}
if(u>=mx) break;
}
tt++;
if(u>=mx) break;
}
for(int j=1;j<=t;j++)
printf("%d\n",a[n[j]]);
return 0;
}