题目链接

六边形

题目描述:

棋盘是由许多个六边形构成的,共有5种不同的六边形编号为1到5,棋盘的生成规则如下:

  1. 从中心的一个六边形开始,逆时针向外生成一个个六边形。
  2. 对于刚生成的一个六边形,我们要确定它的种类,它的种类必须满足与已生成的相邻的六边形不同。
  3. 如果有多个种类可以选,我们选择出现次数最少的种类。
  4. 情况3下还有多个种类可以选,我们选择数字编号最小的。

现在要你求第\(N\)个生成的六边形的编号?前14个六边形生成图如下:

MVCMVVMDDDClean Architecture以及六边形架构 六边形模型_数据结构与算法

输入格式:

第一行:\(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;
}