第2关 - 2018年南海区小学乙组比赛

image.png

395.1、禁止标记(stop) 2018NHOI小乙

题目描述

学校举行春游活动,有些地点是禁止学生活动的,老师知道小C是goc编程高手,想让小C用goc软件画一个禁止标记,如下左图所示:

image.png

图形是由红色的线粗为10线画出来的,圆的半径为100, 2条直径相互垂直并且左右对称。

题解

本题没有要求使用循环,可以使用四条线重复,也可以两条直径为 200 的重复都可以完成。

int main(){
    p.c(1).size(10).o(100);
    p.rt(45).fd(100).bk(100).rt(45);
    p.rt(45).fd(100).bk(100).rt(45);
    p.rt(45).fd(100).bk(100).rt(45);
    p.rt(45).fd(100).bk(100).rt(45);
    
    return 0;
}

396.2、三角形(traingle.cpp)2018NHOI小乙

题目描述

在去郊野的路上,小C的同桌小P拿着一个风车玩具迎风跑动,彩色的风车欢快地转动着。小C觉得很漂亮,决定用 goc软件快速的画出来。如下左图所示:

image.png

图形每条边长均是100,颜色编号分别是1、2、3。

题解

方法一:双循环

int main(){
    
    for(int i = 1;i<=3;i++){
        for(int j = 1; j <= 3; j++){
            p.c(j).fd(100).rt(120);
        }
        p.rt(120);
    }
    return 0;
}

方法二:单循环+特判

int main(){
    int j ;
    for(j = 1; j <= 9; j++){
        int col = (j-1) % 3 + 1; // 1,2,3
        p.c(col).fd(100).rt(120);
    
        if(j % 3 == 0) 
            p.rt(120);
    }
    return 0;
}

397.3、柠檬片(lemon)2018NHOI小乙

题目描述

中午野炊时同学们吃着烤肉,需要清凉的柠檬水解渴。为了增加视觉效果,小C把刚才画的三角形组成的风车形状改造了一下,画出了下面的左图的柠檬片:

image.png

三角形的边长还是100,它们颜色号是5。

大圆的半径为110,小实心圆的半径为20,它颜色号是13。

但是同学们希望能用指定的N个三角形画出更漂亮的柠檬片,请你协助小C完成任务。

输入格式 一个整数N,范围[2,100]。

输出格式 相应的柠檬片图形。第一个三角形第1条边向上,所有三角形旋转角度相等。

输入/输出例子1

输入:

20

输出:

image.png

输入/输出例子2

输入:

5

输出:

image.png

题解

int main(){
    int n;
    cin >> n;
    p.c(5);
    for(int i = 1; i<=n;i++){
        p.fd(100).rt(120);
        p.fd(100).rt(120);
        p.fd(100).rt(120);
        p.rt(360.0 /n);
    }
    p.c(13).o(110).oo(20);
    
    return 0;
}

398.4、山峰(mountain)2018NHOI小乙

题目描述

等待制作柠檬水的时间是无聊的,大家只能欣赏远处的山脉。

image.png

小C觉得可以用N个宽度是20的矩形表示一段远处山脉的高度。比如N=10,高度是50 60 80 70 40 20 55 75 85 90,绘制的图形如下:

image.png

可是小P想到“无限风光在险峰”,特别喜欢山峰,希望把表示山峰的矩形里面画个实心的矩形。注意,只有一个高度的左右2边同时都比它矮时,才叫山峰。上面的例子最终的结果是:

image.png

**输入格式 ** 第一行:1个整数N,范围是[1,10]。

第二行:N个整数,每个整数范围是[10,200]。

输出格式
相应的图形。矩形的宽是20,高度是输入的山高度,山峰用实心矩形。

输入/输出例子1

输入:

5

40 60 50 70 54

输出:

image.png

题解

先存储数据,后进行相邻数判断,首尾可以直接排除。

int arr[15];
int main(){
    cinWin();
    int n,m;
    cin >> n;
    // 绘制全部山峰
    for(int i = 1;i<=n;i++){
        cin >> m;
        p.moveTo(i*20,m/2.0).r(20,m);
        arr[i] = m;
    }
    // 排除首尾,画山峰
    for(int i = 2; i <= n-1; i++){
        m = arr[i];
        //p.moveTo(i*20,m/2.0).text(m);
        
        if(arr[i-1] < m && m > arr[i+1]){            
            p.moveTo(i*20,m/2.0).rr(20,m);
        }
    }
    return 0;
}

399.5、水杯(cup)2018NHOI小乙

题目描述

好消息,柠檬水终于制作好了!一开始柠檬水在红色水杯A里,然后尽量倒入绿色水杯B和青蓝色水杯C中。3水杯的粗细都是一样的(直径都是50),只是高度分别是a、b、c。一开始A水杯是满的,B和C水杯是空的,小C把水杯尽可能的先倒入B;如果B满了后A水杯还有水,就再尽量倒入C水杯。

小C请你用GoC画几个矩形来表示倒水后的每个水杯的高度。例如a=200,b=80,c=100时:

image.png

注意:黑色的数字只是表明尺寸,不用画出。

输入格式
第一行,3个整数a,b,c。 范围[10, 200]。

输出格式
画出3个水杯,颜色分别是1号、3号、4号,高度分别是a,b,c;用实心的部分表示水的高度;水杯之间距离是10。

输入/输出例子1

输入:

150 80 100

输出:

image.png

题解

本题重点要考虑每个杯子是否 满杯。

int main(){
    cinWin();
    int a,b,c,tmp=0;
    cin >> a >> b >> c;
    p.up();
    // 画 A 杯
    p.moveTo(0,a/2.0).r(50,a,1);
    tmp = a -b -c;
    if(tmp >= 0){
        p.moveTo(0, tmp / 2.0).rr(50,tmp,1);
    }
    
    // 画 B 杯
    p.moveTo(60 ,b/2.0).r(50,b,3);
    if(a >= b){
        p.moveTo( 60, b / 2.0).rr(50,b,3);
    }else{
        p.moveTo( 60, a / 2.0).rr(50,a,3);
    }
    
    // 画 c 杯
    p.moveTo( 120 ,c/2.0).r(50,c,4);
    tmp = a -b;
    if(tmp >= c){
        p.moveTo(120, c / 2.0).rr(50,c,4);
    }else if(tmp > 0){
        p.moveTo(120, tmp / 2.0).rr(50,tmp,4);
    }    
    
    
    return 0;
}

400.6、坐船(board)2018NHOI小乙

题目描述

丰盛的午餐过后,大家准备前往湖心岛游玩。湖边码头上有10条相同型号的小船,每条小船最大承载重量是100;并且每只船上只有2个座位,也就是说一条小船最多能坐2个同学。

运送人的小船用一个矩形加1个或2个圆表示,圆的半径为15。

image.png

小C的同伴有N个,他们的体重不一定相同,现在想知道一次运送最多能运多少人?需要最少多少只船?

请把运送人的小船从左向右画出,先画运送一个人的小船,再画运送二个人的小船。

输入格式
第1行:一个整数N,表示人数。范围是[1,20]。

第2行:N个整数,每个整数范围是[10,200]。

输出格式
相应的要求图形。矩形个数就是小船的个数,圆个数就是人的个数。

输入/输出例子1

输入:

6

30 80 40 50 70 110

输出:

image.png

题解

int arr[25];

int main(){
    cinWin();
    int n,x,idx=0;
    cin >> n;
    // 过滤无效数据,并存储 从1开始
    while(n--){
        cin >> x;
        if(x <= 100){
            idx ++; // 有效的数组下标
            arr[idx] = x;
        }
    }
    // 冒泡排序,由大到小 重量大的优先上船,再补重量小的。
    for(int i = 1; i<= idx; i++ ){
        for(int j = idx; j > i; j--){
            if(arr[j]>arr[j-1]){
                int tmp = arr[j];
                arr[j] = arr[j-1];
                arr[j-1] = tmp;
            }
        }
    }
    //测试排序结果
    //for(int i = 1; i<= idx; i++){
    //    cout << arr[i] << " ";
    //}
    
    // rIdx 右游标 ,s1 一个人一条船的数量, s2 两个人一条船的数量
    int rIdx = idx, s1 = 0, s2=0;
    for(int lIdx = 1; lIdx <= idx; lIdx++){
        // 左、右游标重合,退出
        if(rIdx == lIdx) break;
        
        // 计算两个一条船的情况
        if(arr[lIdx] + arr[rIdx] <= 100 && arr[lIdx] != 0){
            arr[lIdx] = 0; 
            arr[rIdx] = 0;
            rIdx --;
            s2 ++;
            
        }
    }
    
    // 遍历剩下的人,即一个人一条船
    for(int i = 1; i<= idx; i++){
        if(arr[i] > 0) s1 ++;
    }
    
    //判断是否超过 10 条船
    if(s1+s2 >= 10) s1 = 10 -  s2;
    cout << s1 << " " << s2 ;
    
    // 开始画图 矩形 宽为 15*2 = 30 ,高为15*4 = 60
    int r = 15;
    for(int i = 0;i<s1; i++){
        p.moveTo(i*30,r).oo(r);
        p.moveTo(i*30,r*2).r(30,60);
    }
    // 要在一人一条船地基础上做偏移后画两个人一条船的图
    for(int i = 0;i< s2; i++){
        p.moveTo((i+s1)*30,r).oo(r);
        p.moveTo((i+s1)*30,r*3).oo(r);
        p.moveTo((i+s1)*30,r*2).r(30,60);
    }
    
    return 0;
}