2019年春季学期第十一周作业
A | Q |
---|---|
这个作业属于那个课程 | C语言程序设计II |
这个作业要求在哪里 | 2019春第十一周作业 |
我在这个课程的目标是 | 能够利用递归函数望城简单的编程题目 |
这个作业在那个具体方面帮助我实现目标 | 了解了递归函数的思路和简单应用并恶气呃利用它王成了汉诺塔问题编程 |
参考文献 | C语言chap9和C语言chap11 |
一、本周完成的作业
题目1.7-1 汉诺塔问题* (10 分****)
汉诺塔是一个源于印度古老传说的益智玩具。据说大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘,大梵天命令僧侣把圆盘移到另一根柱子上,并且规定:在小圆盘上不能放大圆盘,每次只能移动一个圆盘。当所有圆盘都移到另一根柱子上时,世界就会毁灭。
请编写程序,输入汉诺塔圆片的数量,输出移动汉诺塔的步骤。
输入格式:
圆盘数 起始柱 目的柱 过度柱
输出格式:
移动汉诺塔的步骤
每行显示一步操作,具体格式为:
盘片号: 起始柱 -> 目的柱
其中盘片号从 1 开始由小到大顺序编号。
输入样例:
3
a c b
输出样例:
1: a -> c
2: a -> b
1: c -> b
3: a -> c
1: b -> a
2: b -> c
1: a -> c
1).实验代码
#include<stdio.h>
void hanio(int n,char a,char c,char b);
int main (){
int n;
char a,c,b;
scanf("%d\n",&n);
scanf("%c %c %c ",&a,&c,&b);
hanio(n,a,c,b);}
void hanio(int n,char a,char c,char b){
if(n==1){
printf("%d: %c -> %c\n",n,a,c);
}
else{
hanio(n-1,a,b,c);
printf("%d: %c -> %c\n",n,a,c);
hanio(n-1,b,c,a);
}
}
2) .设计思路
mermaid
flowchat
st=>start: 编译与处理函数,声明自定义函数,定义变量
io=>inputoutput: 输入变量
sub=>subroutine: 利用自定义函数来进行操作
e=>end
st->io->sub->e
3).本题调试过程碰到问题及解决办法
问题:老实说这道题没人讲解的话对我来说有难度,不过书上有类似例题,稍作修改即可。可是提交答案部分错误。
解决方法:查阅书籍,比对我的代码与原题的区别,发现我在最后一个输出上输出的盘序号应该是n。改正后正确。
4).运行结果截图
题目2.7-2 估值一亿的AI核心代码 (20 分****)
以上图片来自新浪微博。
本题要求你实现一个稍微更值钱一点的 AI 英文问答程序,规则是:
- 无论用户说什么,首先把对方说的话在一行中原样打印出来;
- 消除原文中多余空格:把相邻单词间的多个空格换成 1 个空格,把行首尾的空格全部删掉,把标点符号前面的空格删掉;
- 把原文中所有大写英文字母变成小写,除了
I
; - 把原文中所有独立的
can you
、could you
对应地换成I can
、I could
—— 这里“独立”是指被空格或标点符号分隔开的单词; - 把原文中所有独立的
I
和me
换成you
; - 把原文中所有的问号
?
换成惊叹号!
; - 在一行中输出替换后的句子作为 AI 的回答。
输入格式:
输入首先在第一行给出不超过 10 的正整数 N,随后 N 行,每行给出一句不超过 1000 个字符的、以回车结尾的用户的对话,对话为非空字符串,仅包括字母、数字、空格、可见的半角标点符号。
输出格式:
按题面要求输出,每个 AI 的回答前要加上 AI: 和一个空格。
输入样例:
6
Hello ?
Good to chat with you
can you speak Chinese?
Really?
Could you show me 5
What Is this prime? I,don 't know
输出样例:
Hello ?
AI: hello!
Good to chat with you
AI: good to chat with you
can you speak Chinese?
AI: I can speak chinese!
Really?
AI: really!
Could you show me 5
AI: I could show you 5
What Is this prime? I,don 't know
AI: what Is this prime! you,don't know
**本题目实在太难,于是跟结对伙伴借鉴,并讨论。思路参考参考. **
1).实验代码
#include<stdio.h>
#include<string.h>
void Echange(char *p);
void Delete(char *p);
void Judge(char *str1);
void Deblank(char *p);
int main()
{
int n,i;
scanf("%d\n",&n);
for(i=0;i<n;i++){
char a[1001];
gets(a);
puts(a);
Echange(a);
Deblank(a);
Delete(a);
printf("AI: ");
Judge(a);
}
return 0;
}
void Deblank(char *p){
int n,i,k=0;
n=strlen(p);
for(i=0;i<n;i++){
if(p[i]==' '){
p[k++]=p[i];
while(p[++i]==' ');
}
p[k++]=p[i];
}
p[k]='\0';
}
void Echange(char *p){
int n,i;
char c;
n=strlen(p);
for(i=0;i<n;i++){
if(p[i]>='A'&&p[i]<='Z'&&p[i]!='I'){
p[i]=p[i]+32;
}
if(p[i]=='?'){
p[i]='!';
}
}
}
void Delete(char *p){
int n,i,k=0;
n=strlen(p);
for(i=0;i<n;i++){
if(p[i]==' '&&i==0){
continue;
}
if(p[i]==' '&&p[i+1]>150){
continue;
}
if(p[i]==' '&&p[i+1]<96&&p[i+1]!='I'&&p[i+1]!='0'&&p[i+1]!='1'&&p[i+1]!='2'&&p[i+1]!='3'&&p[i+1]!='4'&&p[i+1]!='5'&&p[i+1]!='6'&&p[i+1]!='7'&&p[i+1]!='8'&&p[i+1]!='9'){
continue;
}
p[k++]=p[i];
}
p[k]='\0';
}
void Judge(char *str1){
int i=0,b,y;
while(str1[i]!='\0'){
if(str1[i]=='c'&&str1[i+1]=='a'&&str1[i+2]=='n'&&str1[i+3]==' '&&str1[i+4]=='y'&&str1[i+5]=='o'&&str1[i+6]=='u'){
if(((str1[i-1]<'a'||str1[i-1]>'z')&&(str1[i-1]<'A'||str1[i-1]>'Z'))&&((str1[i+7]<'a'||str1[i+7]>'z')&&(str1[i+7]<'A'||str1[i+7]>'Z'))){
str1[i]='I';
str1[i+1]=' ';
str1[i+2]='c';
str1[i+3]='a';
str1[i+4]='n';
str1[i+5]='8';
str1[i+6]='8';
i+=7;
continue;
}
}
if(str1[i]=='c'&&str1[i+1]=='o'&&str1[i+2]=='u'&&str1[i+3]=='l'&&str1[i+4]=='d'&&str1[i+5]==' '&&str1[i+6]=='y'&&str1[i+7]=='o'&&str1[i+8]=='u'){
if(((str1[i-1]<'a'||str1[i-1]>'z')&&(str1[i-1]<'A'||str1[i-1]>'Z'))&&((str1[i+9]<'a'||str1[i+9]>'z')&&(str1[i+9]<'A'||str1[i+9]>'Z'))){
str1[i]='I';
str1[i+1]=' ';
str1[i+2]='c';
str1[i+3]='o';
str1[i+4]='u';
str1[i+5]='l';
str1[i+6]='d';
str1[i+7]='8';
str1[i+8]='8';
i+=7;
continue;
}
}
if(str1[i]=='I'&&((str1[i-1]<'a'||str1[i-1]>'z')&&(str1[i-1]<'A'||str1[i-1]>'Z'))&&((str1[i+1]<'a'||str1[i+1]>'z')&&(str1[i+1]<'A'||str1[i+1]>'Z'))){
str1[i]='7';
}
if((str1[i]=='m'&&str1[i+1]=='e')&&((str1[i-1]<'a'||str1[i-1]>'z')&&(str1[i-1]<'A'||str1[i-1]>'Z'))&&((str1[i+2]<'a'||str1[i+2]>'z')&&(str1[i+2]<'A'||str1[i+2]>'Z'))){
str1[i]='5';
str1[i+1]='6';
i++;
}
i++;
}
y=strlen(str1);
for(i=0;i<y;i++){
if(str1[i]=='8')
continue;
else if(str1[i]=='5'&&str1[i+1]=='6'){
printf("you");
i++;
continue;
}
else if(str1[i]=='7'){
printf("you");
}
else
printf("%c",str1[i]);
}
printf("\n");
}
2) 设计思路
mermaid
flowchat
st=>start: 编译预处理函数,声明自定义函数
sub=>subroutine: 然后利用一些简便的函数来输入输出字符及对话
e=>end
st->op->e
mermaid
flowchat
st=>start: 声明Deblank函数
op=>operation: 利用strlen统计字符长度
io=>inputoutput: 利用一个循环来进行多空格变一空格
sub=>subroutine: 之后再定义Delete函数删除空格
op1=>operation: 之后定义一个函数交换字母,一个for函数和if判断函数即可解决
cond=>condition: 之后再定义Judge函数来判断can you等句型
io1=>inputoutput: 一波操作之后就可以输出了
e=>end: end
st->op->io->sub(right)->op1->cond
cond(yes)->io1
3).本题调试过程碰到问题及解决办法
问题:之前以为定义三位函数就可以搞定的,再经历多次错误之后与结对伙伴讨论之后决定再定义一个将多空格安慰一空格的函数,之后再讨论是否删除空格。
解决方法:结对讨论,得出结论改正之后正确。
4).运行结果截图
题目3.挑战作业:7-3 *八皇后问题 (20 **分****)
在国际象棋中,皇后是最厉害的棋子,可以横走、直走,还可以斜走。棋手马克斯·贝瑟尔 1848 年提出著名的八皇后问题:即在 8 × 8 的棋盘上摆放八个皇后,使其不能互相攻击 —— 即任意两个皇后都不能处于同一行、同一列或同一条斜线上。
现在我们把棋盘扩展到 n × n 的棋盘上摆放 n 个皇后,请问该怎么摆?请编写程序,输入正整数 n,输出全部摆法(棋盘格子空白处显示句点“.”,皇后处显示字母“Q”,每两格之间空一格)。
输入格式
正整数 n (0 < n ≤ 12)
输出格式
若问题有解,则输出全部摆法(两种摆法之间空一行),否则输出 None。
要求:试探的顺序逐行从左往右的顺序进行,请参看输出样例2。
输入样例1
3
输出样例1
None
输入样例2
6
输出样例2
. Q . . . .
. . . Q . .
. . . . . Q
Q . . . . .
. . Q . . .
. . . . Q .
. . Q . . .
. . . . . Q
. Q . . . .
. . . . Q .
Q . . . . .
. . . Q . .
. . . Q . .
Q . . . . .
. . . . Q .
. Q . . . .
. . . . . Q
. . Q . . .
. . . . Q .
. . Q . . .
Q . . . . .
. . . . . Q
. . . Q . .
. Q . . . .
1) 设计思路
本题目实在太难,脑子里只有打给的思路,应给是通过枚举的方法来分类的,先以行为基准,每行一个皇后,然后再此基础上再去讨论列上的皇后是否可以放,依次来进行寻找解法,但是输出实在太麻烦了,写这个代码没有一个下手的点。
之后的迷宫题真的一点思路都没有。
题目4.预习作业:
第十二周的教学内容是:第十一章 指针进阶
请大家查阅资料,思考如下问题:
请举实例解释以下几个概念:数组指针,指针数组,指针函数,函数指针,二级指针,单向链表。(无实例不给分)
数组指针:
举例:
int (*p)[10]; p即为指向数组的指针,又称数组指针。
详见 数组指针
指针数组:
举例:
一个一维指针数组的定义:int *ptr_array[10]。
定义 int p[n];
[]优先级高,先与p结合成为一个数组,再由int说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1时,则p指向下一个数组元素,这样赋值是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 p=a; 这里p表示指针数组第一个元素的值,a的首地址的值。
在网络上查找了之后才知道指针数组和数组指针之间的区别,期间的关系还挺复杂。详见指针数组和数组指针的区别
指针函数:
举例:
int *pfun(int, int);
由于“*”的优先级低于“()”的优先级,因而pfun首先和后面的“()”结合,也就意味着,pfun是一个函数。即:
int *(pfun(int, int));
接着再和前面的“*”结合,说明这个函数的返回值是一个指针。由于前面还有一个int,也就是说,pfun是一个返回值为整型指针的函数。
详见指针函数.
函数指针:
函数指针是指向函数的指针变量。 因此“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上是大体一致的。函数指针有两个用途:调用函数和做函数的参数。
举例:
int func(int x); /* 声明一个函数 */
int (f) (int x); / 声明一个函数指针 */
详见函数指针
二级指针:
A(即B的地址)是指向指针的指针,称为二级指针,用于存放二级指针的变量称为二级指针变量.根据B的不同情况,二级指针又分为指向指针变量的指针和指向数组的指针。
详见二级指针
举例:
int c=2,d=3; int *pc=&c;
pc是指针变量的存储内容,也就是c的地址
*pc就是对指针的解引用,取出这个c这个地址里面的值
单向链表:
单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始;链表是使用指针进行构造的列表;又称为结点列表,因为链表是由一个个结点组装起来的;其中每个结点都有指针成员变量指向列表中的下一个结点;
列表是由结点构成,head指针指向第一个成为表头结点,而终止于最后一个指向NULL的指针。
详见单向链表
举例:
//节点的定义 typedef` `struct` `Node { ``void` `*data; ``//数据域 //链域 ``struct` `Node *next; } NodeStruct, *pNode; pNode head = NULL;
详见单向链表实例
二、学习进度统计和学习感悟
1).学习进度统计
2).学习感悟
本次作业让我感觉难度非凡,深深的感到自己在结构体知识匮乏到了什么程度,几天的时间才能完成作业,思路也不多太难了呀,耗时长,题目难,所幸在这个过程中还是又学习到一些东西的。
(1)本周你学习哪些内容?有哪些收获?
本周学习了函数与结构,其中课上讲解了递归函数。收获嘛,我成功的用递归函数解决了汉诺塔问题,也能看懂之前那看不懂的一些不同的编程解法。
(2)本周所学内容中你觉得哪些地方是难点?对此你做了哪些措施去克服这些难点?
我觉得都贼难的,基础题目都难的一批,八皇后和迷宫题直接就没了思路,代码不知从何下手。我通过网络,室友,结对伙伴和助教来解决这些问题,可是确实太菜了,还是没能用自己的方法解出来。
三、结对编程的过程及优缺点
关于结对编程
本次结对编程地点依旧在寝室,本次结对与室友搭档,过程还是依然比较愉快的,结对编程中我们讨论了第十一周基础作业第二题中代码思路,最终还是得出了这道估值一亿的核心代码。至于八皇后问题,我没能看懂。
优点:1.结对编程更适用于解决一些方向性和拓展容易的问题的问题;2.结对编程中,双方的互动目的在于开启思路,避免单独编程时思维容易阻塞的情况。3.结对编程介于时间和成本,避免走弯路。
缺点:双方的思路被限制了,想核心代码这道题,我们就只讨论出了一种解法,双方的知识面再一个区域没能拓展开。