码迷,mamicode.com
首页 > 其他好文 > 详细

于航特训课:第一课

时间:2018-03-11 21:14:09      阅读:261      评论:0      收藏:0      [点我收藏+]

标签:难题   strcmp   电影   多重   编号   原因   分享   parse   contain   

主办单位

      蓝桥杯全国软件和信息技术专业人才大赛组委会

课程时间

      3月4号-3月31

特训内容

  • 7次算法课,大赛特邀专家精讲历届真题及高频算法
  • 直至赛前,资深算法老师群内作业辅导和答疑
  • 全国参赛小伙伴互助带打
  • 第2次课《递归原理与构造技巧》开课时间:2018年3月7日晚上7:30

 

【课程简介】

    《2018蓝桥杯大赛算法特训》是应广大考生需求,由蓝桥杯全国软件和信息技术专业人才大赛组委会主办,聘请大赛资深顾问专家团成员之一于航老师,通过“图文+音视频”多媒体形式提供的蓝桥杯真题常见算法课程,同时还有持续至赛前的微信群作业和辅导答疑。本次课程提供回放。

【课程目标】

      课程通过7次课共14课时深入浅出的讲解,帮助学生快速理解和掌握蓝桥杯大赛中常见的算法思维、算法技能和解题思路。同时提供持续至赛前的微信群内作业及辅导答疑,帮助学生提高学习效率、锻炼算法思维。

【课程大纲】

1、暴力破解与实用性优先

  • 暴力破解在大赛及企业应用中的重要性
  • 暴力破解中的实用性原则
  • 逆向解法
  • 枚举法

2、递归原理与构造技巧

  • 递归的重要性
  • 递归与循环的关系
  • 递归的构造技巧
  • 递归出口的考虑
  • 参数设计
  • 间接递归

3、典型问题的递归框架

  • 排列问题
  • 组合计数问题
  • 组合枚举问题
  • 递归设计——条条大路通罗马

4、数学知识的运用

  • 并非数学竞赛
  • 进制问题及其巧妙运用
  • 整数与整除问题
  • 欧几里得扩展定理
  • 有理数表示,大数问题

5、博弈问题的思路

  • 递归搜索的基本框架
  • 当有平局时的考虑
  • 尼姆定理
  • 缓存结果

6、分治法与动态规划

  • 分治思想的重要性
  • 二分法是基础
  • 动态规划问题的求解次序
  • 复杂问题的规划

7、图及其他

  • 图与树的关系和转化
  • 图的基本遍历
  • 利用树的性质
  • 线段树与并查集介绍

技术分享图片

 


【关于讲师】

      于航

      中科院计算所
      曾于浙江大学电机系实验室、浙大网新、神州泰岳、中科院计算所等从事软件开发或软件技术培训工作,曾在嘉兴电力、福建电信、扬州联通、中石油物探、中国气象局卫星中心等大中型项目中担任项目组长或技术主管。
从第一届蓝桥杯大赛开始至今,作为大赛顾问专家团成员之一,为大赛提供软件开发技术方面的顾问支持,对蓝桥杯大赛有着深刻的影响和了解。
于老师授课风格轻松幽默,对复杂技术难题理解透彻,讲解深入浅出、层次清晰,喜欢以创新的方式呈现问题关键所在。


【购买须知】
  1. 该课程为付费系列课程,按课程计划定期更新,每节课程可在开课时直播学习,也可反复回听
  2. 购买课程后,请确认您是否已添加小蓝为微信好友,然后私聊小蓝,小蓝将您邀请进入微信算法特训学习群。每次开始上课之前,小蓝会在群里提醒您准备上课
  3. 该课程为虚拟内容服务,购买成功后概不退款,敬请原谅
  4. 如有其它疑问,可点击左下角“咨询”按钮,与客服沟通后再购买

1. 如果您在报名过程中遇到问题,请点我寻找答案。

2. 如果还不能解决您的问题,请直接问小蓝。


【往期活动】

 

蓝桥杯算法特训第一课【实用性原则】源代码

技术分享图片

【内容简介】
本文章内容为【2018蓝桥杯大赛算法特训(软件)系列课程】第一课【实用性原则】中涉及到的课上例题的代码实现,加入赛前特训获取全部课程内容请联系【小蓝】。


【课程中涉及的源代码】
1. 猜年龄
【问题描述】
美国数学家维纳(N.Wiener)智力早熟,11岁就上了大学。
他曾在1935~1936年应邀来中国清华大学讲学。
一次,他参加某个重要会议,年轻的脸孔引人注目。
于是有人询问他的年龄,他回答说:
“我年龄的立方是个4位数。我年龄的4次方是个6位数。这10个数字正好包含了从0到9这10个数字,每个都恰好出现1次。”
请你推算一下,他当时到底有多年轻。
【源代码】
【JAVA:于航】

1
2
3
4
5
6
7
8
9
10
11
public class A{
    public static void main(String[] args){
        for(int i=1; i<100; i++){
            int a = i * i * i;
            int b = a * i;
            if((a+"").length()!=4continue;
            if((b+"").length()!=6continue;            
            System.out.println(i " = " + a " " + b);
        }
    }
}

【C语言:志愿者】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include
#include 

//判断数组里面每一个元素是否相同,相同返回1,不同返回0
int ifDiffInArr(char* arr,int num)
{
    for (int x 0; x < num-1; x++)
    {
        for (int y = x 1; y < num; y++)
        {
            if (arr[x== arr[y])
            {
                return 1;
            }
        }
    }
    return 0;
}
//判断数组1和数组2里面每一个元素是否相同,相同返回1,不同返回0
int ifDiffOfArr(char* arr1int num1,char*arr2,int num2)
{
    for (int x 0; x < num1; x++)
    {
        for (int y 0; y < num2; y++)
        {
            if (arr1[x== arr2[y])
            {
                return 1;
            }
        }
    }
    return 0;
}

void main()
{
    char arr1[4};//保存立方结果4位数的数组
    char arr2[6};//保存4次方结果6位数的数组
    int a, b;//保存立方和4次方的变量
    for (int i 1; i &lt100; i++)//年龄从1到100
    {
        //立方过程
        a= i * i * i;
        //把整形转变为数组类型char*
        itoa(a, arr110);
        //判断arr1数组里面的数字是否重复,重复的话就舍掉i,继续判断下一个i++
        if (ifDiffInArr(arr14== 1)
        {
            continue;
        }

        //4次方过程
        b = a * i;
        //把整形转变为数组类型char*
        itoa(b, arr210);
        //判断arr2数组里面的数字是否重复,重复的话就舍掉i,继续判断下一个i++
        if (ifDiffInArr(arr26== 1)
        {
            continue;
        }

        //判断数组arr1和arr2里面的数字是否重复,重复的话就舍掉i,继续判断下一个i++;不重复的话就是我们要找的年龄,并打印出来。
        if (ifDiffOfArr(arr1,4,arr2,6)==1)
        {
            continue;
        
        else
        {
            printf("计算结果如下:\n\n");
            printf("数学家维纳的年龄是:%d\n\n", i);
            printf("年龄的立方是%d,  \n年龄的4次方是:%d。", a, b);
        }

    }
    
}

2. 罗马数字
【问题描述】
古罗马帝国开创了辉煌的人类文明,但他们的数字表示法的确有些繁琐,尤其在表示大数的时候,现在看起来简直不能忍受,所以在现代很少使用了。
之所以这样,不是因为发明表示法的人的智力的问题,而是因为一个宗教的原因,当时的宗教禁止在数字中出现0的概念!
罗马数字的表示主要依赖以下几个基本符号:

I –> 1
V –> 5
X –> 10
L –> 50
C –> 100
D –> 500
M –> 1000

这里,我们只介绍一下1000以内的数字的表示法。
单个符号重复多少次,就表示多少倍。最多重复3次。
比如:CCC表示300 XX表示20,但150并不用LLL表示,这个规则仅适用于I X C M。

如果相邻级别的大单位在右,小单位在左,表示大单位中扣除小单位。
比如:IX表示9 IV表示4 XL表示40 
49 = XLIX

更多的示例参见下表,你找到规律了吗? 
I = 1 
II = 2
III = 3
IV = 4
V = 5
VI = 6
VII = 7
VIII = 8
IX = 9 
X = 10
XI = 11
XII = 12
XIII = 13
XIV = 14
XV = 15
XVI = 16
XVII = 17
XVIII = 18
XIX = 19
XX = 20
XXI = 21
XXII = 22
XXIX = 29
XXX = 30
XXXIV = 34
XXXV = 35
XXXIX = 39
XL = 40
L = 50
LI = 51
LV = 55
LX = 60
LXV = 65
LXXX = 80
XC = 90
XCIII = 93
XCV = 95
XCVIII = 98
XCIX = 99
C = 100
CC = 200
CCC = 300
CD = 400
D = 500
DC = 600
DCC = 700
DCCC = 800
CM = 900
CMXCIX = 999

本题目的要求是:请编写程序,由用户输入若干个罗马数字串,程序输出对应的十进制表示。

输入格式是:第一行是整数n,表示接下来有n个罗马数字(n<100)。
以后每行一个罗马数字。罗马数字大小不超过999。
要求程序输出n行,就是罗马数字对应的十进制数据。

例如,用户输入:
3
LXXX
XCIII
DCCII

则程序应该输出:
80
93
702
【源代码】
【JAVA:于航】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//罗马数字的枚举解法
public class A{
    
    public static int romeNum(String s){
        int sum 0;
        for(int i=0; i&lt;s.length(); i++)char c = s.charAt(i)if(c==‘I‘) sum += 1if(c==‘V‘) sum += 5if(c==‘X‘) sum += 10if(c==‘L‘) sum += 50if(c==‘C‘) sum += 100if(c==‘D‘) sum += 500if(c==‘M‘) sum += 1000// 补偿 if(s.indexOf("IV")&gt;=0) sum -= 2;
        if(s.indexOf("IX")&gt;=0) sum -= 2;
        if(s.indexOf("XL")&gt;=0) sum -= 20;
        if(s.indexOf("XC")&gt;=0) sum -= 20;
        if(s.indexOf("CD")&gt;=0) sum -= 200;
        if(s.indexOf("CM")&gt;=0) sum -= 200;
        
        return sum;
    }
    
    public static void main(String[] args){
        System.out.println(romeNum("MCCCXIV"));
        System.out.println(romeNum("CMXCIX"));
    }
}
//罗马数字的逆向解法
public class NiXiang
{
    static String NumRoman(int x){
        int a = x 1000;  // 千位
        int b = x 1000 100;  //百位
        int c = x 100 10;  // 十位
        int d = x 10;
        
        String s "";
        
        if(a==1) s += "M";
        if(a==2) s += "MM";
        if(a==3) s += "MMM";
        
        if(b==1) s += "C";
        if(b==2) s += "CC";
        if(b==3) s += "CCC";
        if(b==4) s += "CD";
        if(b==5) s += "D";
        if(b==6) s += "DC";
        if(b==7) s += "DCC";
        if(b==8) s += "DCCC";
        if(b==9) s += "CM";
        
        if(c==1) s += "X";
        if(c==2) s += "XX";
        if(c==3) s += "XXX";
        if(c==4) s += "XL";
        if(c==5) s += "L";
        if(c==6) s += "LX";
        if(c==7) s += "LXX";
        if(c==8) s += "LXXX";
        if(c==9) s += "XC";
                
        if(d==1) s += "I";
        if(d==2) s += "II";
        if(d==3) s += "III";
        if(d==4) s += "IV";
        if(d==5) s += "V";
        if(d==6) s += "VI";
        if(d==7) s += "VII";
        if(d==8) s += "VIII";
        if(d==9) s += "IX";
        
        return s;   
    }
     
    static boolean RomanNumOK(String s){
        for(int i=0; i&lt;4000; i++){
            if(s.equals(NumRoman(i))return true;        
}        
return false;    
}        

public static void main(String[] args){        
System.out.println(RomanNumOK("CCXLIX"));         
System.out.println(RomanNumOK("CCXXLIX"));        
//System.out.println(NumRoman(3009));    
}
}

【C语言:志愿者】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include 
#include 
#include 
// 罗马数字的枚举解法
int romeNum(char* s,int num)
{
        int sum 0;
        for (int i 0; i &lt; num; i++)
        {
            char c = s[i];
            if (c == ‘I‘
                sum += 1;
            if (c == ‘V‘
                sum += 5;
            if (c == ‘X‘
                sum += 10;
            if (c == ‘L‘
                sum += 50;
            if (c == ‘C‘
                sum += 100;
            if (c == ‘D‘
                sum += 500;
            if (c == ‘M‘
                sum += 1000;
        }

        // 补偿
        if (strstr(s,"IV"!= NULL
            sum -= 2;
        if (strstr(s"IX"!= NULL)
            sum -= 2;
        if (strstr(s"XL"!= NULL)
            sum -= 20;
        if (strstr(s"XC"!= NULL)
            sum -= 20;
        if (strstr(s"CD"!= NULL)
            sum -= 200;
        if (strstr(s"CM"!= NULL)
            sum -= 200;

        return sum;
}

void main()
{
    

        printf("%d\n",romeNum("MCCCXIV",7));
        printf("%d\n", romeNum("CMXCIX"6));

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 
char s[10];

char* NumRoman(int x)
{
    int a = x 1000;  // 
    int b = x 1000 100;  //
    int c = x 100 10;  // 
    int d = x 10;

    for (int x 0; x &lt1024;x++)
    {
        s[x‘0‘;
    }

    if (a == 1)
        strcat(s"M");
    if (a == 2)
        strcat(s"MM");
    if (a == 3)
        strcat(s"MMM");


    if (b == 1)
        strcat(s"C");
    if (b == 2)
        strcat(s"CC");
    if (b == 3)
        strcat(s"CCC");
    if (b == 4)
        strcat(s"CD");
    if (b == 5)
        strcat(s"D");
    if (b == 6)
        strcat(s"DC");
    if (b == 7)
        strcat(s"DCC");
    if (b == 8)
        strcat(s"DCCC");
    if (b == 9)
        strcat(s"CM");

    if (c == 1)
        strcat(s"X");
    if (c == 2)
        strcat(s"XX");
    if (c == 3)
        strcat(s"XXX");
    if (c == 4)
        strcat(s"XL");
    if (c == 5)
        strcat(s"L");
    if (c == 6);
    strcat(s"LX");
    if (c == 7)
        strcat(s"LXX");
    if (c == 8)
        strcat(s"LXXX");
    if (c == 9)
        strcat(s"XC");

    if (d == 1)
        strcat(s"I");
    if (d == 2)
        strcat(s"II");
    if (d == 3)
        strcat(s"III");
    if (d == 4)
        strcat(s"IV");
    if (d == 5)
        strcat(s"V");
    if (d == 6)
        strcat(s"VI");
    if (d == 7)
        strcat(s"VII");
    if (d == 8)
        strcat(s"VIII");
    if (d == 9)
        strcat(s"IX");

    return s;
}

int  RomanNumOK(char * s)
{
    for (int i 0; i &lt4000; i++)
    {
        char *p = NumRoman(i);
        int x strcmp(p, s);
        /*free(p);*/
        if (!x)
            return 1;
    }
    return 0;
}

void main()
{

    int num1 = RomanNumOK("CCXLIX");
    int num2 = RomanNumOK("CCXXLIX");
    //System.out.println(NumRoman(3009));
}

3. 九宫幻方
【问题描述】

小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分。
三阶幻方指的是将1~9不重复的填入一个3*3的矩阵当中,使得每一行、每一列和每一条对角线的和都是相同的。
三阶幻方又被称作九宫格,在小学奥数里有一句非常有名的口诀:
“二四为肩,六八为足,左三右七,戴九履一,五居其中”,
通过这样的一句口诀就能够非常完美的构造出一个九宫格来。
4 9 2
3 5 7
8 1 6
有意思的是,所有的三阶幻方,都可以通过这样一个九宫格进行若干镜像和旋转操作之后得到。
现在小明准备将一个三阶幻方(不一定是上图中的那个)中的一些数抹掉,交给邻居家的小朋友来进行还原,并且希望她能够判断出究竟是不是只有一个解。

而你呢,也被小明交付了同样的任务,但是不同的是,你需要写一个程序~

输入格式:
输入仅包含单组测试数据。
每组测试数据为一个3*3的矩阵,其中为0的部分表示被小明抹去的部分。
对于100%的数据,满足给出的矩阵至少能还原出一组可行的三阶幻方。

输出格式:
如果仅能还原出一组可行的三阶幻方,则将其输出,否则输出“Too Many”(不包含引号)。

样例输入
0 7 2
0 5 0
0 3 0

样例输出
6 7 2
1 5 9
8 3 4
【源代码】
【JAVA:于航】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/*
4 9 2
3 5 7
8 1 6
"492357816"

8 3 4
1 5 9
6 7 2
"834159672"

0 7 2
0 5 0
0 3 0

*/
public class A
{
    static boolean test(String std, String s){
        for(int i=0; i&lt;std.length(); i++){
            if(std.charAt(i== s.charAt(i)continue;
            if(s.charAt(i)==‘0‘continue;
            return false;
        }
        
        return true;
    }
    
    public static void main(String[] args){
        
        String s "072050030";
        
        String[] ss {
            "492357816",
            "834159672",
            "618753294",
            "276951438",
            "294753618",
            "438951276",
            "816357492",
            "672159834"
        };
        
        for(int i=0; i&lt;ss.length; i++){
            if(test(ss[i],s)){
                System.out.println(ss[i].substring(0,3));
                System.out.println(ss[i].substring(3,6));
                System.out.println(ss[i].substring(6,9));               
            }
        }
    }
}

【C语言:志愿者】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include 
#include 

int test(char* stdint num1char* sint num2)
{
    for (int i 0; i &lt; num1; i++)
    {
        if (std[i== s[i])
            continue;
        if (s[i== ‘0‘
            continue;
        return 0;
    }
    return 1;
}

char * myItoa(int num)
{
    char * p malloc(1024 1);
    itoa(num,p10);
    return p;
}

void main3()
{
    char* arr1 = myItoa(172050030);
    arr1[0‘0‘;

    char *  p0 = myItoa(492357816);
    char *  p1 = myItoa(834159672);
    char *  p2 = myItoa(618753294);
    char *  p3 = myItoa(276951438);
    char *  p4 = myItoa(294753618);
    char *  p5 = myItoa(438951276);
    char *  p6 = myItoa(816357492);
    char *  p7 = myItoa(672159834);
    char *  pp[8{ p0, p1, p2, p3, p4, p5, p6, p7 };


    for (int i 0; i &lt8; i++)
    {
        if (test(pp[i]7, arr1,7))
        {
            for (int x 0; x &lt3;x++)
            {
                printf("%c ", pp[i][x]);
            }
            printf("\n");
            for (int x 3; x &lt6; x++)
            {
                printf("%c ", pp[i][x]);
            }
            printf("\n");
            for (int x 6; x &lt9; x++)
            {
                printf("%c ", pp[i][x]);
            }
            printf("\n");

        }
    }
    for (int i 0; i &lt8; i++)
    {
        if (pp[i!= NULL)
        {
            free(pp[i]);
        }
    }
}

4. 魔方旋转
【问题描述】
魔方可以对它的6个面自由旋转。

我们来操作一个2阶魔方(如图1所示):
为了描述方便,我们为它建立了坐标系。

各个面的初始状态如下:
x轴正向:绿
x轴反向:蓝
y轴正向:红
y轴反向:橙
z轴正向:白
z轴反向:黄

假设我们规定,只能对该魔方进行3种操作。分别标记为:
x 表示在x轴正向做顺时针旋转
y 表示在y轴正向做顺时针旋转
z 表示在z轴正向做顺时针旋转

xyz 则表示顺序执行x,y,z 3个操作

题目的要求是:
用户从键盘输入一个串,表示操作序列。
程序输出:距离我们最近的那个小方块的3个面的颜色。
顺序是:x面,y面,z面。

例如:在初始状态,应该输出:
绿红白

初始状态下,如果用户输入:
x
则应该输出:
绿白橙

初始状态下,如果用户输入:
zyx
则应该输出:
红白绿
技术分享图片

面的标号
技术分享图片

模仿旋转示意图

【源代码】
【JAVA:于航】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/*
  二阶魔方的各个面给一个唯一编号:
  
         16 17
         19 18
        ------- 
 12 13 |  0  1 |  4  5 |  8  9
 15 14 |  3  2 |  7  6 | 11 10
        -------
         20 21
         23 22
         
         上
       左前右后
         下
         
x操作:(0,1,2,3)  (4,21,14,19)  (7,20,13,18)
y操作:(4,5,6,7)  (1,17,11,21)  (2,18,8,22)
z操作:(16,17,18,19) (0,12,8,4)  (1,13,9,5)         
*/

public class A
{
    static int[][] transx={{0,1,2,3},{4,21,14,19},{7,20,13,18}};
    static int[][] transy={{4,5,6,7},{1,17,11,21},{2,18,8,22}};
    static int[][] transz={{16,17,18,19},{0,12,8,4},{1,13,9,5}};
    
    static char[] op(char[] a,int[][] trans){
        char[] b = java.util.Arrays.copyOf(a,a.length);
        
        for(int i=0; i&lt;trans.length; i++){
            b[trans[i][1]= a[trans[i][0]];
            b[trans[i][2]= a[trans[i][1]];
            b[trans[i][3]= a[trans[i][2]];
            b[trans[i][0]= a[trans[i][3]];
        }
        return b;
    }
    
    static char[] op(char[] a, String s){
        char[] b = java.util.Arrays.copyOf(a, a.length);
        for(int i=0; i&lt;s.length(); i++){
            if(s.charAt(i)==‘x‘) b = op(b, transx);
            if(s.charAt(i)==‘y‘) b = op(b, transy);
            if(s.charAt(i)==‘z‘) b = op(b, transz);
        }
        return b;
    }
    
    public static void main(String[] args){
        char[] init =  {‘绿‘,‘绿‘,‘绿‘,‘绿‘,
                        ‘红‘,‘红‘,‘红‘,‘红‘,
                        ‘蓝‘,‘蓝‘,‘蓝‘,‘蓝‘,
                        ‘橙‘,‘橙‘,‘橙‘,‘橙‘,
                        ‘白‘,‘白‘,‘白‘,‘白‘,
                        ‘黄‘,‘黄‘,‘黄‘,‘黄‘,};
                        
        //char[] b = op(init, "xyxyzzxyxyzz");
        char[] b = op(init, "x");
        System.out.println(""+b[1]+b[4]+b[18]);
        
    }
}

【C语言:志愿者】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include 
#include 
#include 

int transx[4][4012}4211419 }7201318 };
int transy[4][4456}1171121 }218822 };
int transz[4][416171819 }0128}1139};

char * op(char *p,int num1,int pp[4][4],int num2)
{
    char * arrb malloc(num1*sizeof(char));
    strncpy(arrb, p, num1);

    for (int i 0; i &lt; num2; i++)
    {
        arrb[pp[i][1]= p[pp[i][0]];
        arrb[pp[i][2]= p[pp[i][1]];
        arrb[pp[i][3]= p[pp[i][2]];
        arrb[pp[i][0]= p[pp[i][3]];
    }
    return arrb;
}
void printfCh(char a)
{
    switch (a)
    {
    case ‘0‘:
        printf("绿");
        break;
    case ‘1‘:
        printf("红");
        break;
    case ‘2‘:
        printf("蓝");
        break;
    case ‘3‘:
        printf("橙");
        break;
    case ‘4‘:
        printf("白");
        break;
    case ‘5‘:
        printf("黄");
        break;
    default:
        break;
    }

}

char * op1(char *aint num1char *s,int num2)
{
    char * arrb malloc(num1*sizeof(char));
    strncpy(arrb, a, num1);

    for (int i 0; i &lt; num2; i++)
    {
        if (s[i== ‘x‘
            arrb = op(arrb, num1, transx3);
        if (s[i== ‘y‘
            arrb = op(arrb, num1, transy3);
        if (s[i== ‘z‘
            arrb = op(arrb, num1, transz3);
    }
    return arrb;
}

void main(){
    char init[‘0‘‘0‘‘0‘‘0‘,
        ‘1‘‘1‘‘1‘‘1‘,
        ‘2‘‘2‘‘2‘‘2‘,
        ‘3‘‘3‘‘3‘‘3‘,
        ‘4‘‘4‘‘4‘‘4‘,
        ‘5‘‘5‘‘5‘‘5‘};
    
        //char[] b = op(init, "xyxyzzxyxyzz");
        char* b = op1(init24"x"1);
        printfCh(b[1]);
        printfCh(b[4]);
        printfCh(b[18]);
;

    }

【课后作业】
【信用卡号的验证】

当你输入信用卡号码的时候,有没有担心输错了而造成损失呢?其实可以不必这么担心,因为并不是一个随便的信用卡号码都是合法的,它必须通过Luhn算法来验证通过。
该校验的过程:
1、从卡号最后一位数字开始,逆向将奇数位(1、3、5等等)相加。
2、从卡号最后一位数字开始,逆向将偶数位数字,先乘以2(如果乘积为两位数,则将其减去9),再求和。
3、将奇数位总和加上偶数位总和,结果应该可以被10整除。
例如,卡号是:5432123456788881

则,奇数位和=35
偶数位乘以2(有些要减去9)的结果:1 6 2 6 1 5 7 7,求和=35。
最后35+35=70 可以被10整除,认定校验通过。

请编写一个程序,从键盘输入卡号,然后判断是否校验通过。通过显示:“成功”,否则显示“失败”。
比如,用户输入:356827027232780
程序输出:成功

【参考测试用例】
356406010024817 成功
358973017867744 成功
356827027232781 失败
306406010024817 失败
358973017867754 失败

【代码示例】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class A
{
    // s: 待验证的卡号
    static boolean f(String s){
        int sum 0;
        for(int i=0; i&lt;s.length(); i++)int x = s.charAt(s.length()-i-1)-‘0‘if(i%2==1){ x = x 2if(x&gt;=10) x -= 9;
            }
            sum += x;
        }
        return sum 10 == 0;
    }
    
    public static void main(String[] args){
        System.out.println(f("356827027232780"));
        System.out.println(f("356406010024817"));
        System.out.println(f("358973017867744"));
        System.out.println(f("356827027232781"));
        System.out.println(f("306406010024817"));
        System.out.println(f("358973017867754"));       
    }
}

public class B
{
    // s: 待验证的卡号
    static boolean f(String s){
        int[] EV {0,2,4,6,8,1,3,5,7,9};
        int sum 0;
        for(int i=0; i&lt;s.length(); i++){
            int x = s.charAt(s.length()-i-1)-‘0‘;
            if(i%2==1) x = EV[x];
            sum += x;
        }
        return sum 10 == 0;
    }
    
    public static void main(String[] args){
        System.out.println(f("356827027232780"));
        System.out.println(f("356406010024817"));
        System.out.println(f("358973017867744"));
        System.out.println(f("356827027232781"));
        System.out.println(f("306406010024817"));
        System.out.println(f("358973017867754"));       
    }
}

如果您需要更多课程内容和讲解视频,请联系小蓝

 

 

蓝桥杯算法特训第二课【递归原理与构造技巧】源代码

技术分享图片

【内容简介】
本文章内容为【2018蓝桥杯大赛算法特训(软件)系列课程】第二课【递归原理与构造技巧】中涉及到的课上例题的代码实现,加入赛前算法特训获取全部课程内容请联系【小蓝】。


【课程中涉及的源代码】
1. 串的翻转
【问题描述】
【源代码】
【JAVA:于航】

 

1
2
3
4
5
6
7
8
9
10
11
public class A
{
    static String f(String s){
        if(s.length()&lt;=1return s;
        return f(s.substring(1)+ s.charAt(0);
    }
    
    public static void main(String[] args){
        System.out.println(f("abcde"));
    }
}

【C:志愿者】

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 

char * f(char * sint num)
{
    if (num &lt;= 1)
    {
        return s;
    }
    else
    {
        char *p (char *)malloc(num+1);
        memset(p0, num+1);
        strcpy(p, s+1);
        char *pp = f(p, num-1);         
        strcpy(p, pp);
        if (p!=pp)
            free(pp);
        strncpy(p+num-1,s,1);       
        return p;
    }
}

void main()
{
    char arr[100"abcde";
    printf("%s", f(arr5));

}

 


2. 循环改递归
【问题描述】
【源代码】
【JAVA:于航】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class A
{
    static void f(int a, int b){
        for(int i=a; i&lt;=b; i++){
            System.out.println(i);
        }
    }
    
    static void g(int a, int b){
        if(a&lt;b) g(a,b-1);
        System.out.println(b);
    }
    
    public static void main(String[] args){
        //f(1,10);  
        g(1,10);
    }
}

【C语言:志愿者】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 

void f2(int aint b)
{
    for (int i = a; i &lt;= b; i++){
        printf("%d ",i);
    }
}

void g2(int aint b)
{
    if (a &lt; b
        g2(a, b 1);
    printf("%d   ",b);
}

void main()
{
    //f2(1,10); 
    g2(110);
}

 


3. 出栈次序
【问题描述】
X星球特别讲究秩序,所有道路都是单行线。
一个甲壳虫车队,共16辆车,按照编号先后发车,夹在其它车流中,缓缓前行。
路边有个死胡同,只能容一辆车通过,是临时的检查站,如图所示。
技术分享图片
X星球太死板,要求每辆路过的车必须进入检查站,也可能不检查就放行,也可能仔细检查。
如果车辆进入检查站和离开的次序可以任意交错。那么,该车队再次上路后,可能的次序有多少种?
为了方便起见,假设检查站可容纳任意数量的汽车。
显然,如果车队只有1辆车,可能次序1种;2辆车可能次序2种;3辆车可能次序5种。
【源代码】
【JAVA:于航】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
  如果进栈次序为:1 2 3 4 5 。。。
  出栈次序有多少种情况?
  
*/

public class A
{
    // n 个等着进栈,栈中有m个
    static int f(int n, int m)
    {
        if(n==0return 1;
        if(m==0return f(n-1,1);
        return f(n,m-1+ f(n-1, m+1);
    }
    
    static int f(int n)
    {
        return f(n, 0);
    }
    
    public static void main(String[] args)
    {
        for(int i=1; i&lt;17; i++){
            System.out.println(i ": " + f(i));
        }
    }
}

【C语言:志愿者】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
/*
如果进栈次序为:1 2 3 4 5 。。。
出栈次序有多少种情况?

*/

    // n 个等着进栈,栈中有m个
    int f3(int nint m)
    {
        if (n == 0
            return 1;
        if (m == 0
            return f3(n 11);
        return 
            f3(n, m 1+ f3(n 1, m 1);
    }

    int f5(int n)
    {
        return f3(n0);
    }

    void main()
    {
        for (int i 1; i&lt;17; i++)
        {
            printf("%d : %d \n", i, f5(i));
        }
    }

 


4. 第39级台阶
【问题描述】

小明刚刚看完电影《第39级台阶》。离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!
站在台阶前,他突然又想着一个问题:
如果我每一步只能迈上1个或2个台阶。先迈左脚,然后左右交替,最后一步是迈右脚,也就是说一共要走偶数步。那么,上完39级台阶,有多少种不同的上法呢?
请你利用计算机的优势,帮助小明寻找答案。

【源代码】
【JAVA:于航】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class A
{
    // 奇数步
    static long g(int n)
    {
        if(n==0return 0;
        if(n==1return 1;
        //if(n==2) return 1;
        
        return f(n-1+ f(n-2);
    }
    
    // 偶数步
    static long f(int n)
    {
        if(n==0return 1;
        if(n==1return 0;
        //if(n==2) return 1;
        
        return g(n-1+ g(n-2);
    }
    
    public static void main(String[] args)
    {
        System.out.println(f(5));
        System.out.println(f(39));
    }
}

【C语言:志愿者】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 

long ff(int n);
    // 奇数步
long gg(int n)
{
    if (n == 0
        return 0;
    if (n == 1
        return 1;
    /*if(n==2)
        return 1;*/
    return ff(n 1+ ff(n 2);
}

    // 偶数步
long ff(int n)
{
    if (n == 0
        return 1;
    if (n == 1
        return 0;
    /*if(n==2)
        return 1;*/
    return gg(n 1+ gg(n 2);
}

void main()
{
        printf("%d \n",ff(5));
        printf("%d ", ff(39));
}

5. 算式填符号
【问题描述】

匪警请拨110,即使手机欠费也可拨通!
为了保障社会秩序,保护人民群众生命财产安全,警察叔叔需要与罪犯斗智斗勇,因而需要经常性地进行体力训练和智力训练!

某批警察叔叔正在进行智力训练:
1 2 3 4 5 6 7 8 9 = 110

请看上边的算式,为了使等式成立,需要在数字间填入加号或者减号(可以不填,但不能填入其它符号)。之间没有填入符号的数字组合成一个数,例如:12+34+56+7-8+9 就是一种合格的填法;123+4+5+67-89 是另一个可能的答案。

请你利用计算机的优势,帮助警察叔叔快速找到所有答案。
每个答案占一行。形如:
12+34+56+7-8+9
123+4+5+67-89
……

【源代码】
【JAVA:于航】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class SuanShi
{
    //a: 参加计算的元素
    //k: 目前考虑的元素下标
    //so: 合成好的结果串
    //goal: 计算目标
    static void f(int[] a, int k, String so, int goal){
        if(k==0){
            if(a[0== goal){
                System.out.println(a[0]+so);
            }
            return;
        }
        
        f(a,k-1,"+"+a[k]+so, goal-a[k]);
        f(a,k-1,"-"+a[k]+so, goal+a[k]);
        int old = a[k-1];
        a[k-1Integer.parseInt("" + a[k-1+ a[k]);
        f(a,k-1,so,goal);
        a[k-1= old;
    }
    
    public static void main(String[] args){
        int[] a {1,2,3,4,5,6,7,8,9};      
        f(a,8,"",110);
    }
}

【C语言:志愿者】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 

    //a: 参加计算的元素
    //k: 目前考虑的元素下标
    //so: 合成好的结果串
    //goal: char
    void fk(int *aint kchar *sint goal){
        if (k == 0){
            if (a[0== goal){
                printf("%d%s\n",a[0],s);
            }
            return;
        }

        char * p malloc(k 1);
        memset(p0, k 1);

        p[0‘+‘;
        _itoa(a[k], p+110);
        int x strlen(p);
        strcat(p+x, s);     
        fk(a, k 1, p, goal - a[k]);

        p[0‘-‘;
        fk(a, k 1, p, goal + a[k]);


        int old = a[k 1];
        char ak[1024};
        char ak2[1024};
        _itoa(a[k 1], ak10);
        _itoa(a[k], ak210);
        strcat(ak, ak2);
        a[k 1atoi(ak);
        memset(p0, k 1);
        strcat(p, s);
        fk(a, k 1, p, goal);
        a[k 1= old;
    }


    
    void main()
    {
        int a[12345678};
        fk(a8""110);
    }

 


6. 找钱问题
【问题描述】

公园票价为5角。假设每位游客只持有两种币值的货币:5角、1元。
再假设持有5角的有m人,持有1元的有n人。
由于特殊情况,开始的时候,售票员没有零钱可找。
我们想知道这m+n名游客以什么样的顺序购票则可以顺利完成购票过程。
显然,m < n的时候,无论如何都不能完成;
m>=n的时候,有些情况也不行。比如,第一个购票的乘客就持有1元。
请计算出这m+n名游客所有可能顺利完成购票的不同情况的组合数目。
注意:只关心5角和1元交替出现的次序的不同排列,持有同样币值的两名游客交换位置并不算做一种新的情况来计数。

【源代码】
【JAVA:于航】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//考虑最后一个人
public class ZhaoQian1
{
    //m: 持有5角的
    //n: 持有1元的
    static int f(int m, int n){
        if(m&lt;nreturn 0;
        if(m==1return 1;
        if(n==0return 1;
            
        return f(m-1,n+ f(m,n-1);
    }
    
    public static void main(String[] args){
        System.out.println(f(2,2));
        System.out.println(f(3,2));
        System.out.println(f(5,3));
    }
}

//考虑第一个人
public class ZhaoQian2
{
    //m: 持有5角的
    //n: 持有1元的
    //t: 售票员手里有多少个5角的
    static int f(int m, int n, int t){
        if(m+t&lt;nreturn 0if(m==0return 1if(n==0return 1int r = f(m-1,n,t+1)if(t&gt;0) r += f(m,n-1,t-1)
        return r;
    }
    
    public static void main(String[] args){
        System.out.println(f(2,2,0));
        System.out.println(f(3,2,0));
        System.out.println(f(5,3,0));
    }
}

【C语言:志愿者】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 
//考虑最后一个人
//m: 持有5角的
//n: 持有1元的
int f6(int mint n)
{
    if (m &lt; n
        return 0;
    if (m == 1
        return 1;
    if (n == 0
        return 1;

    return f6(m 1, n+ f6(m, n 1);
}

void main(){
    printf("%d \n",f6(22));
    printf("%d \n",f6(32));
    printf("%d \n",f6(53));

}

//==========================================

#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 
//考虑第一个人
//m: 持有5角的
//n: 持有1元的
//t: 售票员手里有多少个5角的
int fn(int mint nint t)
{
    if (m + t&lt;nreturn 0if (m == 0return 1if (n == 0return 1int r = fn(m 1, n, t 1)if (t&gt;0
        r += fn(m, n 1, t 1);
    return r;
}

void main()
{
    printf("%d \n", fn(220));
    printf("%d \n", fn(320));
    printf("%d \n", fn(530));

}

7. 振兴中华
【问题描述】
小明参加了学校的趣味运动会,其中的一个项目是:跳格子。
地上画着一些格子,每个格子里写一个字,如下所示:(也可参见下图)

从我做起振
我做起振兴
做起振兴中
起振兴中华
技术分享图片
比赛时,先站在左上角的写着“从”字的格子里,可以横向或纵向跳到相邻的格子里,但不能跳到对角的格子或其它位置。一直要跳到“华”字结束。

要求跳过的路线刚好构成“从我做起振兴中华”这句话。
请你帮助小明算一算他一共有多少种可能的跳跃路线呢?

【源代码】
【JAVA:于航】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class A
{
    static int f(int m, int n)
    {
        if(m==|| n==1return 1;
        
        return f(m-1,n+ f(m,n-1);
    }
    
    public static void main(String[] args)
    {
        System.out.println(f(5,4));
        //System.out.println(f(3,2));
    }

}

【C语言:志愿者】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 
int f7(int mint n)
{
    if (m == || n == 1
        return 1;
    return f7(m 1, n+ f7(m, n 1);
}

void main7()
{
    printf("%d \n", f7(54));
    //printf("%d \n", f7(3, 2));

于航特训课:第一课

标签:难题   strcmp   电影   多重   编号   原因   分享   parse   contain   

原文地址:https://www.cnblogs.com/passion-sky/p/8545343.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!