XTU1441素数螺旋

题目描述:

绘制一个逆时钟的螺旋线,一开始方向向右,边长依次为第i个素数,即2,3,5,7,⋯ 。 使用_ 表示横线,| 表示竖线,要求图形的每行行尾无多余的空格。

比如n=5时,

 _____
|     |
|     |
|   __|
|
|
|
|___________

输入格式:

第一行是一个整数T (1≤T≤20),表示样例的个数。

以后每行一个整数n(1≤n≤168)。

输出格式:

依次按要求输出对应的图形。每个样例之后输出一个空行。

样例输入:

4
1
2
3
4

样例输出:

__

  |
  |
__|

_____
     |
     |
   __|

 _____
|     |
|     |
|   __|
|
|
|
|

提示:

第168个素数是997。

大体思路:

本题想要直接输出答案非常困难,所以我们可以使用画地图的方式来预处理出一个巨型大地图,再根据输入来选定大地图中的一部分进行输出。

根据上述思路,产生了以下几个过程:

1.先筛选出素数才能处理大地图

2.预处理出大地图,我们发现大地图从起点向四周扩展,所以有必要让起点的坐标大一点(防止画图的时候数组越界)

3.根据输入选定地图位置

4.处理行末空格

5.注意再多打一个换行

具体实现:

对于第一步,欧拉筛选出素数(欧拉筛可能难以理解,使用埃氏筛法亦可)

isprime[1] = 1;
for(int i=2;i<=N;i++){
    if(!isprime[i]) prime[++cnt] = i;
    for(int j=1;j<=cnt && i*prime[j]<=N;j++){
        isprime[i*prime[j]] = 1;
        if(i%prime[j] == 0) break;
    }
}

对于第二步,我选择的画地图的起始点是(2000, 2000),且让这个大地图的大小为4000 * 4000。同时为了后面框选地图大小方便,我在处理一下地图坐标的数组

for(int i=0;i<=4000;i++){
    px[i] = 2000;//表示输入的数为i时地图的右边界
    py[i] = 2000;//表示输入的数为i时地图的上边界
    pxm[i] = 2000;//表示输入的数为i时地图的左边界
    pym[i] = 2000;//表示输入的数为i时地图的下边界
    for(int j=1;j<=4000;j++){
        mapp[i][j] = ' ';
    }
}

预处理大地图:

// 右:1 上:2 左:3 下:4 
int dir = 1;//从1开始画的时候先向右走
int posx=2000,posy=2000;//起始坐标
int cnt = 1;
for(int i=1;i<=168;i++){
    dir = i % 4;//此时往哪个方向画
    //下面四行意思是:新框选的地图大小绝对不可能比之前框选的小,所以继承
    px[i] = px[i-1];
    py[i] = py[i-1];
    pxm[i] = pxm[i-1];
    pym[i] = pym[i-1];
    for(int j=1;j<=prime[i];j++){
        //下面四行意思是:时刻更新新框选的地图
        px[i] = max(px[i],posx);
        py[i] = max(py[i],posy);
        pxm[i] = min(pxm[i],posx);
        pym[i] = min(pym[i],posy);
        //根据题意画出地图,更新画笔的坐标
        if(dir==1){
            mapp[posx][posy] = '_';
            posx++;
        }
        if(dir==2){
            mapp[posx][posy] = '|';
            posy--;
        }
        if(dir==3) {
            mapp[posx][posy] = '_';
            posx--;
        }
        if(dir==0){
            mapp[posx][posy] = '|';
            posy++;
        }
    }
    //根据题目要求特殊处理
    if(dir == 2){
        posx--;
    }
    if(dir == 3){
        posy++;
    }
    if(dir==0){
        posy--;
        posx++;
    }
}

这样我们就把地图框选出来了,之后再绘制地图:

void draw(int n){
    int spaces = 0;//记录空格数目
    //从上往下、从左往右遍历地图
    for(int i=pym[n];i<=py[n];i++){
        spaces = 0;
        for(int j=pxm[n];j<=px[n];j++){
            if(n%4==0){
                //推断n为4的倍数的时候,之后左侧需要伸出一根腿
                if(i==py[n]){
                    printf("|");
                    break;
                }
            }
            if(mapp[j][i]!=' '){
                //将记录的空格一股脑输出出来,因为已经判断出后面还有字符——不是行末
                for(int p=1;p<=spaces;p++) printf(" ");
                spaces = 0;
            }else{
                spaces++;continue;    
            }
            printf("%c",mapp[j][i]);
        }
        printf("\n");
    }
    printf("\n");
}

最后主程序只需要处理好各个部分就行了

euler();
int T;
scanf("%d",&T);
while(T--){
    int n;
    scanf("%d",&n);
    draw(n);
}

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值