未知:六边形——题解

(接上题,反正是一起做的那么故事情节也接上吧嘻嘻嘻)
“正好,带我去一趟天线崖。”
”你确定?!你都说了都要暴雨了,前几天的暴雨……“
”是啊,你还抱怨整天闷在家里啥事也没干呢,结果就剩下我在刷题而你整天再睡觉。“
因为山脉的阻隔,所以他们只能乘坐小船到达那里。
而给他们租小船的人,开出了很高的价钱,但是。
”你们帮我解决一个问题,我就免费带你们去你们想去的地方。“
他指了指酒馆前面做的一个汉子,汉子的桌子上摆着一个很大的六边形棋盘。
————————————————————————
时间限制: 1S 空间限制:256M
棋盘是由许多个六边形构成的,共有5种不同的六边形编号为1到5,棋盘的生成规
则如下:
1.从中心的一个六边形开始,逆时针向外生成一个个六边形。
2.对于刚生成的一个六边形,我们要确定它的种类,它的种类必须满足与已生成的相
邻的六边形不同。
3.如果有多个种类可以选,我们选择出现次数最少的种类。
4.情况3下还有多个种类可以选,我们选择数字编号最小的。
现在要你求第N个生成的六边形的编号。
输入格式:
第一行: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
————————————————
今天的模拟都很有意思?!
这道明显是找规律的题却意外的不好找规律。
思考一下,恩……大概是六边形使我们石乐志。
但是大家的普遍打法都是靠六边形转换成矩形,然后打表。
我们想一想……
这道题难道真的无规律可循吗?!
当答案找不到规律时,我们想想能够导出答案的东西是否有规律。
是啊,如果我们知道每一个六边形的相邻情况的话完全模拟就可以解决啊!

这就是规律:
遵从题意,我们从起点开始,按放数字的顺序依次编号为1,2……
接下来,我们知道与1相邻的有2,3,4,5,6,7
那么因为1相邻着2,所以2相邻着1
又因为2肯定相邻着3
所以与2相邻有1,3
然而还差四个点为7,8,9,10

好的上述的内容总结为三条规律:
对于点i,找到与它所有相邻的六个点
已知i-1的点所邻的最大编号的点为k
1.从1~i-1,如果有与i相邻的点,就加上
2.i+1一定与i相邻
3.上述两步操作完后所得的相邻点的个数为n<6,那么接下来的点分别为k+0,k+1……直到n==6为止

其实我们还可以证明这个的正确性(然而再写下去我的手就抽筋了,证明就交给大家了?)

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
int l[10001][7]={0};
int f[10001]={0};
int cnt[6]={0};
int ji[10001]={0};
bool ok[10001]={0};
void chu(){
    for(int i=1;i<=6;i++){
        l[1][i]=i+1;
    }
    ok[1]=1;
    for(int i=1;i<=10000;i++){
        if(ok[i]==1){
            for(int j=1;j<=6;j++){
                int k=l[i][j];
                if(k>10000||ok[k]==1)continue;
                ji[k]++;
                l[k][ji[k]]=i;
                if(ji[k]==6)ok[k]=1;
            }
        }else{
            ji[i]++;
            l[i][ji[i]]=i+1;
            if(ji[i]==6){
                ok[i]=1;
                i--;
                continue;
            }else{
                int hah=0;
                for(int j=ji[i]+1;j<=6;j++){
                    l[i][j]=l[i-1][6]+hah;
                    hah++;
                }
            }
            ji[i]=6;ok[i]=1;
            i--;
        }
    }
    return;
}
bool ha[7];
int main(){
    freopen("hex.in","r",stdin);
    freopen("hex.out","w",stdout);
    chu();
    int t;
    scanf("%d",&t);
    int maxn=1;
    while(t--){
        int n;
        scanf("%d",&n);
        if(f[n]!=0){
            printf("%d\n",f[n]);
            continue;
        }else{
            for(int i=maxn;i<=n;i++){
                memset(ha,0,sizeof(ha));
                for(int j=1;j<=6;j++){
                    if(l[i][j]>10000)continue;
                    ha[f[l[i][j]]]=1;
                }
                int minn=2147483647;
                for(int j=1;j<=5;j++){
                    if(ha[j]==0){
                        minn=min(minn,cnt[j]);
                    }
                }
                for(int j=1;j<=5;j++){
                    if(ha[j]==0&&minn==cnt[j]){
                        f[i]=j;
                        cnt[j]++;
                        break;
                    }
                }
            }
        }
        printf("%d\n",f[n]);
        maxn=max(maxn,n+1);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值