zoukankan      html  css  js  c++  java
  • 2017-第八届蓝桥杯大赛个人赛省赛(软件类)真题 C大学A组

    返回目录

    题目一览:

    1.迷宫

    2.跳蚱蜢

    3.魔方状态

    4.方格分割

    5.字母组串

    6.最大公共子串

    7.正则问题

    8.包子凑数

    9.分巧克力

    10.油漆面积

    1.迷宫

    X星球的一处迷宫游乐场建在某个小山坡上。
    它是由10x10相互连通的小房间组成的。

    房间的地板上写着一个很大的字母。
    我们假设玩家是面朝上坡的方向站立,则:
    L表示走到左边的房间,
    R表示走到右边的房间,
    U表示走到上坡方向的房间,
    D表示走到下坡方向的房间。

    X星球的居民有点懒,不愿意费力思考。
    他们更喜欢玩运气类的游戏。这个游戏也是如此!

    开始的时候,直升机把100名玩家放入一个个小房间内。
    玩家一定要按照地上的字母移动。

    迷宫地图如下:
    ------------
    UDDLUULRUL
    UURLLLRRRU
    RRUURLDLRD
    RUDDDDUUUU
    URUDLLRRUU
    DURLRLDLRL
    ULLURLLRDU
    RDLULLRDDD
    UUDDUDUDLL
    ULRDLUURRR
    ------------

    请你计算一下,最后,有多少玩家会走出迷宫?
    而不是在里边兜圈子。

    请提交该整数,表示走出迷宫的玩家数目,不要填写任何多余的内容。

    如果你还没明白游戏规则,可以参看一个简化的4x4迷宫的解说图:
    p1.png

    思路:模拟即可。走出判定:出界;走不出判定:走到了原来走过的点。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 string s[101];
     5 bool flag, vis[11][11], Break;
     6 int Ans;
     7 
     8 void dfs(int x, int y) {
     9     if(x<0 || x>9 || y<0 || y>9) { // 走出 
    10         flag = true;
    11         return ;
    12     }
    13     if(vis[x][y]) { // 走到了走过的点 
    14         Break = true;
    15         return ;
    16     }
    17     if(Break || flag) return;
    18     vis[x][y] = true; // 标记 
    19     if(s[x][y] == 'U') x--; // 下一步 
    20     else if(s[x][y] == 'D') x++;
    21     else if(s[x][y] == 'L') y--;
    22     else if(s[x][y] == 'R') y++;
    23     dfs(x, y);
    24 }
    25 
    26 int main() {
    27     for(int i=0; i<10; ++i) 
    28         cin >> s[i];
    29     for(int i=0; i<10; ++i) {
    30         for(int j=0; j<10; ++j) {
    31             flag = Break = false;// 每次都要初始化 
    32             memset(vis, false, sizeof(vis)); 
    33             dfs(i, j);
    34             if(flag) Ans++;
    35         }
    36     }
    37     printf("%d
    ", Ans);
    38     return 0;
    39 }
    1.迷宫

    答案:31

    2.跳蚱蜢

    如图 p1.png 所示:

    有9只盘子,排成1个圆圈。
    其中8只盘子内装着8只蚱蜢,有一个是空盘。
    我们把这些蚱蜢顺时针编号为 1~8

    每只蚱蜢都可以跳到相邻的空盘中,
    也可以再用点力,越过一个相邻的蚱蜢跳到空盘中。

    请你计算一下,如果要使得蚱蜢们的队形改为按照逆时针排列,
    并且保持空盘的位置不变(也就是1-8换位,2-7换位,...),至少要经过多少次跳跃?

    注意:要求提交的是一个整数,请不要填写任何多余内容或说明文

    思路:宽搜,每次将四种跳法后的局面判重加入即可。

     1 #include <bits/stdc++.h>
     2 #include <queue> 
     3 using namespace std;
     4 
     5 char ss[1010][1010];
     6 int len;
     7 set<string> vis;
     8 
     9 struct Node {
    10     string s; // 当前局面 
    11     int pos, cnt; // 空格位置  到达该局面的步数 
    12 };
    13 
    14 void bfs() {
    15     queue<Node> q;
    16     Node head;
    17     head.pos = head.cnt = 0; head.s = "012345678"; // 初始局面 
    18     q.push(head);
    19     while(!q.empty()) {
    20         head = q.front(); q.pop();
    21         if(head.s == "087654321") { // 到达目标局面 
    22             printf("Ans = %d
    ", head.cnt);
    23             return ;
    24         }
    25         for(int i=-2; i<=2; ++i) { // 四种跳法 
    26             if(i == 0) continue;
    27             string str = head.s;
    28             int tmp = head.pos;
    29             swap(str[tmp], str[(tmp+i+9)%9]);
    30             Node tail;
    31             if(vis.count(str) == 0) { // 当前局面之前没有 
    32                 vis.insert(str);
    33                 tail.s = str;
    34                 tail.pos = (tmp+i+9)%9;
    35                 tail.cnt = head.cnt+1;
    36                 q.push(tail);
    37             }
    38         }
    39     }
    40 }
    41 
    42 int main() {
    43     bfs();
    44     return 0;
    45 }
    2.跳蚱蜢

    答案:20

    3.魔方状态

    二阶魔方就是只有2层的魔方,只由8个小块组成。
    如图p1.png所示。

    小明很淘气,他只喜欢3种颜色,所有把家里的二阶魔方重新涂了颜色,如下:

    前面:橙色
    右面:绿色
    上面:黄色
    左面:绿色
    下面:橙色
    后面:黄色

    请你计算一下,这样的魔方被打乱后,一共有多少种不同的状态。

    如果两个状态经过魔方的整体旋转后,各个面的颜色都一致,则认为是同一状态。

    请提交表示状态数的整数,不要填写任何多余内容或说明文字。

    答案:229878

    4.方格分割

    6x6的方格,沿着格子的边线剪开成两部分。
    要求这两部分的形状完全相同。

    如图:p1.png, p2.png, p3.png 就是可行的分割法。

    试计算:
    包括这3种分法在内,一共有多少种不同的分割方法。
    注意:旋转对称的属于同一种分割法。

    请提交该整数,不要填写任何多余的内容或说明文字。

    思路:这道题很巧妙,不按照格子搜索,搜索点,从中心点开始深搜,同时标记对称的点,当一边搜完时就是一个可行的方案。最后记得/4.

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int Ans;
     5 int u[4] = {-1, 0, 0, 1}, v[4] = {0, -1, 1, 0};
     6 bool vis[10][10];
     7 
     8 bool check(int x, int y) {
     9     if(vis[x][y]) return false; // 走过了 
    10     if(x<0 || x>6) return false; // 出界 
    11     if(y<0 || y>6) return false;
    12     return true;
    13 }
    14 
    15 void dfs(int x, int y) {
    16     if(x==0 || x==6 || y==0 || y==6) { // 搜到边界了 
    17         Ans ++;
    18         return ;
    19     }
    20     vis[x][y] = vis[6-x][6-y] = true; // 标记
    21     for(int i=0; i<4; ++i) { // 四个方向 
    22         int xx = x + u[i];
    23         int yy = y + v[i];
    24         if(check(xx, yy)) {
    25             dfs(xx, yy);
    26         }
    27     }
    28     vis[x][y] = vis[6-x][6-y] = false; // 回溯 
    29 }
    30 
    31 int main() {
    32     memset(vis, false, sizeof(vis));
    33     dfs(3, 3); // 从中心点开始搜索 
    34     printf("%d
    ", Ans/4); // 有重复 
    35     return 0;
    36 }
    4.方格分割

    答案:509

    5.字母组串

    由 A,B,C 这3个字母就可以组成许多串。
    比如:"A","AB","ABC","ABA","AACBB" ....

    现在,小明正在思考一个问题:
    如果每个字母的个数有限定,能组成多少个已知长度的串呢?

    他请好朋友来帮忙,很快得到了代码,
    解决方案超级简单,然而最重要的部分却语焉不详。

    请仔细分析源码,填写划线部分缺少的内容。

     1 #include <stdio.h>
     2 
     3 // a个A,b个B,c个C 字母,能组成多少个不同的长度为n的串。
     4 int f(int a, int b, int c, int n)
     5 {
     6     if(a<0 || b<0 || c<0) return 0;
     7     if(n==0) return 1; 
     8     
     9     return _________________;  // 填空
    10 }
    11 
    12 int main()
    13 {
    14     printf("%d
    ", f(1,1,1,2));
    15     printf("%d
    ", f(1,2,3,3));
    16     return 0;
    17 }

    对于上面的测试数据,小明口算的结果应该是:
    6
    19

    注意:只填写划线部分缺少的代码,不要提交任何多余内容或说明性文字。

    思路:递归题,通过第7行知道n是目前需要填充的长度,那么我们每次填充一个A、B或者C,那么其个数需要减1,目前需要填充的长度也要减1.

    答案:

    f(a-1, b, c, n-1)+f(a, b-1, c, n-1)+f(a, b, c-1, n-1)

    6.最大公共子串

    最大公共子串长度问题就是:
    求两个串的所有子串中能够匹配上的最大长度是多少。

    比如:"abcdkkk" 和 "baabcdadabc",
    可以找到的最长的公共子串是"abcd",所以最大公共子串长度为4。

    下面的程序是采用矩阵法进行求解的,这对串的规模不大的情况还是比较有效的解法。

    请分析该解法的思路,并补全划线部分缺失的代码。

     1 #include <stdio.h>
     2 #include <string.h>
     3 
     4 #define N 256
     5 int f(const char* s1, const char* s2)
     6 {
     7     int a[N][N];
     8     int len1 = strlen(s1);
     9     int len2 = strlen(s2);
    10     int i,j;
    11     
    12     memset(a,0,sizeof(int)*N*N);
    13     int max = 0;
    14     for(i=1; i<=len1; i++){
    15         for(j=1; j<=len2; j++){
    16             if(s1[i-1]==s2[j-1]) {
    17                 a[i][j] = ______;  //填空
    18                 if(a[i][j] > max) max = a[i][j];
    19             }
    20         }
    21     }
    22     
    23     return max;
    24 }
    25 
    26 int main()
    27 {
    28     printf("%d
    ", f("abcdkkk", "baabcdadabc"));
    29     return 0;
    30 }

    注意:只提交缺少的代码,不要提交已有的代码和符号。也不要提交说明性文字。

    思路:DP题,看第16行,当前两个字符相同,那么以他俩结尾的长度就是以前一个字符结尾的长度+1。针对最长公共子序列的问题可以看着。(待补)

    答案:

    a[i-1][j-1] + 1

    7.正则问题

    考虑一种简单的正则表达式:
    只由 x ( ) | 组成的正则表达式。
    小明想求出这个正则表达式能接受的最长字符串的长度。

    例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是: xxxxxx,长度是6。

    输入
    ----
    一个由x()|组成的正则表达式。输入长度不超过100,保证合法。

    输出
    ----
    这个正则表达式能接受的最长字符串的长度。

    例如,
    输入:
    ((xx|xxx)x|(x|xx))xx

    程序应该输出:
    6

    资源约定:
    峰值内存消耗(含虚拟机) < 256M
    CPU消耗 < 1000ms


    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

    注意:
    main函数需要返回0;
    只使用ANSI C/ANSI C++ 标准;
    不要调用依赖于编译环境或操作系统的特殊函数。
    所有依赖的函数必须明确地在源文件中 #include <xxx>
    不能通过工程设置而省略常用头文件。

    提交程序时,注意选择所期望的语言类型和编译器类型。

    思路:首先理解样例的6是这么来的,|是取左右里较多的哪一个。((xx|xxx)x|(x|xx))xx,

    第一步去括号里面左侧的括号:(xxx x|(x|xx))xx

    第二步去括号里面右侧的括号:(xxx x| xx)xx

    第三步去外层括号:xxx x xx

    答案就是6.

    代码的话就是递归,然后是四种情况。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 char s[105];
     5 int pos = 0, len;
     6 
     7 int f() {
     8     int Now_sum = 0, Max_sum = 0;
     9     while(pos < len) {
    10         if(s[pos] == '(') { // 左括号,位置加一 等待右括号 
    11             pos++;
    12             Now_sum += f();
    13         } 
    14         else if(s[pos] == 'x') { // x 位置加一 计数器加一 
    15             pos ++;
    16             Now_sum ++;
    17         }
    18         else if(s[pos] == ')') { // 左括号 位置加一 中断这次递归 
    19             pos ++;
    20             break;
    21         }
    22         else if(s[pos] == '|') { // | 位置加一  
    23             pos++;
    24             Max_sum = max(Max_sum, Now_sum); // 保留较大值 
    25             Now_sum = 0; //计数器清零 
    26         }
    27     }
    28     Max_sum = max(Max_sum, Now_sum); //保留较大值 
    29     return Max_sum;
    30 }
    31 
    32 int main() {
    33     scanf("%s", s);
    34     len = strlen(s);
    35     int Ans = f();
    36     printf("%d
    ", Ans);
    37     return 0;
    38 }
    7.正则问题

    8.包子凑数

    小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有N种蒸笼,其中第i种蒸笼恰好能放Ai个包子。每种蒸笼都有非常多笼,可以认为是无限笼。

    每当有顾客想买X个包子,卖包子的大叔就会迅速选出若干笼包子来,使得这若干笼中恰好一共有X个包子。比如一共有3种蒸笼,分别能放3、4和5个包子。当顾客想买11个包子时,大叔就会选2笼3个的再加1笼5个的(也可能选出1笼3个的再加2笼4个的)。

    当然有时包子大叔无论如何也凑不出顾客想买的数量。比如一共有3种蒸笼,分别能放4、5和6个包子。而顾客想买7个包子时,大叔就凑不出来了。

    小明想知道一共有多少种数目是包子大叔凑不出来的。

    输入
    ----
    第一行包含一个整数N。(1 <= N <= 100)
    以下N行每行包含一个整数Ai。(1 <= Ai <= 100)

    输出
    ----
    一个整数代表答案。如果凑不出的数目有无限多个,输出INF。

    例如,
    输入:
    2
    4
    5

    程序应该输出:
    6

    再例如,
    输入:
    2
    4
    6

    程序应该输出:
    INF

    样例解释:
    对于样例1,凑不出的数目包括:1, 2, 3, 6, 7, 11。
    对于样例2,所有奇数都凑不出来,所以有无限多个。

    资源约定:
    峰值内存消耗(含虚拟机) < 256M
    CPU消耗 < 1000ms


    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

    注意:
    main函数需要返回0;
    只使用ANSI C/ANSI C++ 标准;
    不要调用依赖于编译环境或操作系统的特殊函数。
    所有依赖的函数必须明确地在源文件中 #include <xxx>
    不能通过工程设置而省略常用头文件。

    提交程序时,注意选择所期望的语言类型和编译器类型。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int n, a[1010], Ans, g;
     5 bool f[10010];
     6 
     7 int gcd(int a, int b) {
     8     return b? gcd(b, a%b):a;
     9 }
    10 
    11 int main() {
    12     cin >> n;
    13     memset(f, false, sizeof(f));
    14     f[0] = true;
    15     for(int i=0; i<n; ++i) {
    16         scanf("%d", &a[i]);
    17         if(i == 0) g = a[i];
    18         else g = gcd(g, a[i]);
    19         for(int j=0; j<10000; ++j)
    20             if(f[j]) f[j+a[i]] = true;
    21     }
    22     if(g != 1) {
    23         puts("INF");
    24         return 0;
    25     }
    26     bool flag = false;
    27     int tot = 0;
    28     for(int i=0; i<10000; ++i) {
    29         if(!f[i]) Ans++;
    30     }
    31     printf("%d
    ", Ans);
    32     return 0;
    33 }
    8.包子凑数

    9.分巧克力

    儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
    小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形。

    为了公平起见,小明需要从这 N 块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:

    1. 形状是正方形,边长是整数
    2. 大小相同

    例如一块6x5的巧克力可以切出6块2x2的巧克力或者2块3x3的巧克力。

    当然小朋友们都希望得到的巧克力尽可能大,你能帮小Hi计算出最大的边长是多少么?

    输入
    第一行包含两个整数N和K。(1 <= N, K <= 100000)
    以下N行每行包含两个整数Hi和Wi。(1 <= Hi, Wi <= 100000)
    输入保证每位小朋友至少能获得一块1x1的巧克力。

    输出
    输出切出的正方形巧克力最大可能的边长。

    样例输入:
    2 10
    6 5
    5 6

    样例输出:
    2

    资源约定:
    峰值内存消耗(含虚拟机) < 256M
    CPU消耗 < 1000ms


    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

    注意:
    main函数需要返回0;
    只使用ANSI C/ANSI C++ 标准;
    不要调用依赖于编译环境或操作系统的特殊函数。
    所有依赖的函数必须明确地在源文件中 #include <xxx>
    不能通过工程设置而省略常用头文件。

    提交程序时,注意选择所期望的语言类型和编译器类型。

    方法一:要求边长最大那么我们就从最大开始枚举边长,不断减小来找到满足条件的边长。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int N, K;
     5 
     6 struct QKL {
     7     int h, w;
     8 }qkl[100010];
     9 
    10 int main() { // 暴力 
    11     cin >> N >> K;
    12     for(int i=0; i<N; ++i)
    13         scanf("%d%d", &qkl[i].h, &qkl[i].w);
    14     int Ans = 100000;
    15     while(Ans >= 1) { // 枚举边长 
    16         int cnt = 0; // 当前边长下能切多少 
    17         for(int i=0; i<N; ++i) // N块巧克力 
    18             cnt += (qkl[i].h/Ans) * (qkl[i].w/Ans);
    19         if(cnt >= K) { // 由于我们从大到小枚举,第一个满足的就是最大的 
    20             printf("%d
    ", Ans);
    21             return 0;
    22         }
    23         Ans --;
    24     }
    25     return 0;
    26 }
    9.分巧克力-方法一-超时

    方法二:优化方法一,我们使用二分法,每次二分出一个边长,不够分说明边长大了,我们就减小一点。分的多,我们看看能不能使边长大一点。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int N, K;
     5 
     6 struct QKL {
     7     int h, w;
     8 }qkl[100010];
     9 
    10 bool check(int x) {
    11     int cnt = 0;
    12     for(int i=0; i<N; ++i) 
    13         cnt += (qkl[i].h/x) * (qkl[i].w/x);
    14     if(cnt >= K) return true; // 能分成K块 
    15     else return false; // 分不成K块 
    16 }
    17 
    18 int main() { // 二分 
    19     cin >> N >> K;
    20     for(int i=0; i<N; ++i)
    21         scanf("%d%d", &qkl[i].h, &qkl[i].w);
    22     int l = 0, r = 100001;
    23     while(l <= r) {
    24         int m = (l+r) / 2;
    25         if(check(m)) l = m+1; // 边长可以再大一点 
    26         else r = m-1; // 边长大了,小一点 
    27     }
    28     printf("%d
    ", l-1);
    29     return 0;
    30 } 
    9.分巧克力-方法二

    10.油漆面积

    X星球的一批考古机器人正在一片废墟上考古。
    该区域的地面坚硬如石、平整如镜。
    管理人员为方便,建立了标准的直角坐标系。

    每个机器人都各有特长、身怀绝技。它们感兴趣的内容也不相同。
    经过各种测量,每个机器人都会报告一个或多个矩形区域,作为优先考古的区域。

    矩形的表示格式为(x1,y1,x2,y2),代表矩形的两个对角点坐标。

    为了醒目,总部要求对所有机器人选中的矩形区域涂黄色油漆。
    小明并不需要当油漆工,只是他需要计算一下,一共要耗费多少油漆。

    其实这也不难,只要算出所有矩形覆盖的区域一共有多大面积就可以了。
    注意,各个矩形间可能重叠。

    本题的输入为若干矩形,要求输出其覆盖的总面积。

    输入格式:
    第一行,一个整数n,表示有多少个矩形(1<=n<10000)
    接下来的n行,每行有4个整数x1 y1 x2 y2,空格分开,表示矩形的两个对角顶点坐标。
    (0<= x1,y1,x2,y2 <=10000)

    输出格式:
    一行一个整数,表示矩形覆盖的总面积。

    例如,
    输入:
    3
    1 5 10 10
    3 1 20 20
    2 7 15 17

    程序应该输出:
    340

    再例如,
    输入:
    3
    5 2 10 6
    2 7 12 10
    8 1 15 15

    程序应该输出:
    128

    资源约定:
    峰值内存消耗(含虚拟机) < 256M
    CPU消耗 < 2000ms


    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

    注意:
    main函数需要返回0;
    只使用ANSI C/ANSI C++ 标准;
    不要调用依赖于编译环境或操作系统的特殊函数。
    所有依赖的函数必须明确地在源文件中 #include <xxx>
    不能通过工程设置而省略常用头文件。

    提交程序时,注意选择所期望的语言类型和编译器类型。

    方法一:直接模拟,设置一个二维数组初始化为false,需要涂油漆的地方改为true,最后统计true的个数即可。由于官方数据较水,该方法不会超时。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int N, Ans = 0;
     5 bool vis[10006][10006];
     6 
     7 void work(int x, int y, int xx, int yy) {
     8     for(int i=x; i<xx; ++i) 
     9         for(int j=y; j<yy; ++j)
    10             vis[i][j] = true;
    11 }
    12 
    13 int main() {
    14     cin >> N;
    15     memset(vis, false, sizeof(vis));
    16     for(int i=1; i<=N; ++i) {
    17         int x, y, xx, yy;
    18         scanf("%d%d%d%d", &x, &y, &xx, &yy);
    19         work(x, y, xx, yy);
    20     }
    21     for(int i=0; i<10005; ++i) 
    22         for(int j=0; j<10005; ++j)
    23             if(vis[i][j]) {
    24                 //printf("%d %d
    ", i, j);
    25                 Ans++;
    26             }
    27     printf("%d
    ", Ans);
    28     return 0;
    29 }
    10.油漆面积-方法一

    方法二:正解解法:线段树+扫描线。

    先挖个坑

    PS:官方有个数据是错的,正确答案是4909,而给的答案是3796.想AC的话可以特判一下。面向数据编程

  • 相关阅读:
    页面自动化
    phantomjs 开发爬虫框架
    javascript 正则表达式
    javascript/TypeScript 生成GUID
    Plupload 上传控件使用指南
    文件上传详解 (HTML FILE)
    Bootstrap File Input 中文文档
    找个地记录和分享工作上的点滴
    最短路 + 记录路径 之 zoj 1456 Minimum Transport Cost (hdu 1385)
    求解单源最短路问题:Bellman-Ford算法(可判负权回路)详解 之 poj 3268 Silver Cow Party
  • 原文地址:https://www.cnblogs.com/Marginalin/p/12641742.html
Copyright © 2011-2022 走看看