题目描述:
绘制一个逆时钟的螺旋线,一开始方向向右,边长依次为第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);
}