2020秋季C语言综合练习题(节选)

路标

题目描述
公元13世纪上半叶,蒙古军队一路西征杀向欧洲。在进军途中,蒙古骑兵以旗为单位沿一条道路相继开进。为了给后面的队伍指路,每当遇到一个道路分叉处时,就在路旁堆石头堆作路标,堆一堆石头表示直行,堆两堆石头表示右转,堆三堆石头表示左转。试用C语言编写一个程序,计算出通过的路口数目。假设每个相邻路口间路段的长度基本相等且开始的方向向西(以此判断第一个路口,即出发时向哪个方向走),用输出eswn四个字母或其组合来确定最终的地点相对于出发地(即第一个路口)的方位。
输入格式:
只有一行(以’\n’结束),分别用1、2和3表示路口遇到的石碓的数量,最多有20个路口。
输出格式:
只有一行,由一个数字和一个字母或两个字母组合分别构成路口的数目和最终地点与出发地的方位。如果需要输出两个字母,则输出字母按照字典序输出(不用考虑回到原始出发点的情况)

输入样例

31

输出样例

2,s
#include<stdio.h>
int main() {
	int x=0,y=0;//x、y表示在平面直角坐标系中的当前坐标。
	int face=3;//face表示当前的朝向,3表示朝西。
	char str[21];
	scanf("%s",str);
	for(int i=0; str[i]!='\0'; i++) {
		if(str[i]=='2')face++;//右转
		if(str[i]=='3')face--;//左转
		face=(face+4)%4;//使得face∈[0,4)
		//位置向相应朝向前进
		if(face==0)y++;//北
		if(face==1)x++;//东
		if(face==2)y--;//南
		if(face==3)x--;//西
	}
	printf("%d,",strlen(str));
	//字典序输出当前位置相对于起始位置的方向
	if(x>0) printf("e");
	if(y>0) printf("n");
	if(y<0) printf("s");
	if(x<0) printf("w");
	return 0;
}

大整数进制转换

二进制转十进制
输入为一个二进制大整数(大整数大于0,不带符号,无前导0,至少1位数字,且不超过100位数字)。要求将该整数转换成十进制数,并输出。
建议:用字符数组存储大整数。
输入样例1
1001001100101100000001011010010
输出样例1
1234567890
十进制转二进制
输入为一个十进制大整数(大整数大于0,不带符号,无前导0,至少1位数字,且不超过100位数字)。要求将该整数转换成二进制数,并输出。
建议:用字符数组存储大整数。
输入样例2
1234567890
输出样例2
1001001100101100000001011010010
//这两道题思路是一样的,都是利用秦九韶算法和高精度算法。所以写了个通用的。
#include <stdio.h>
#define DST 10//目标进制
#define SRC 2//原始进制
#define IN_SIZE 100//原始进制的最大位数
#define OUT_SIZE 31//目标进制的最小位数,应保证为log(DST,SRC^IN_SIZE).
//该程序可以通过修改以上4个宏来实现10以内的所有进制之间的转换。10以上的需要额外定义符号。
int main(){
	char src[IN_SIZE+1]={0};
	int dst[OUT_SIZE]={0};
	scanf("%s",src);
	for(int i=0;src[i]!='\0';i++){//算法的主体是秦九韶算法,运用这一算法可以使每一个中间值都很小,不会超过int的最大范围。
		for(int i=0;i<OUT_SIZE;i++){//乘
			dst[i]*=SRC;
		}
		dst[0]+=src[i]-'0';//加
		for(int i=0;i<OUT_SIZE-1;i++){//按照目标进制进位
			dst[i+1]+=dst[i]/DST;
			dst[i]%=DST;
		}
	}
	int i=OUT_SIZE;
	for(i=OUT_SIZE-1;dst[i]==0&&i>0;i--);//从最高位到最低位找,找到第一个不是0的元素.
	do{//找到以后逆序输出。
		printf("%d",dst[i]);
	}while(i--);
	return 0;
} 

Josephus问题:一个热土豆引发的故事

题目描述
在食品匮乏的年代,能吃到一个土豆已经是很幸福的事情,如果这个土豆还是热乎的,就更好了。但土豆只有一个,有很多人都想吃,怎么分配呢? Josephus想了个办法,把N个人从1到N编号,围坐成一个圆圈。然后从1号开始传递一个热土豆,经过M次传递后,拿着热土豆的人被清除离座,围坐的圆圈紧缩,由坐在被清除的人后面那个人拿起热土豆继续进行游戏,最后剩下的那个人取胜。例如,M=0和N=5时,剩下的是5号。如果M=1和N=5时,被清除的人的顺序是2,4,1,5,最后剩下的是3号。由于M的值事先并不知道,所以到底谁是人生赢家,能够吃到这个热土豆呢?
输入格式:
1行,2个整数,中间由逗号隔开。第一个整数表示N个人(0<N<=100),第二个整数表示M(O<=M<=N)。
输出格式:
1行,N个整数,中间用逗号隔开。这些数字表示离开圆圈的人的顺序,用其编号表示。最后一个就是最终剩下的吃热土豆的人。

输入样例

5,1

输出样例

2,4,1,5,3

以下三种思路供大家参考。

//一个复杂的做法。这个做法不删除任何元素,只是在传递的时候跳过被移走的人。
#include <stdio.h>
#include <stdbool.h> 
int main(){
	int N,M;
	bool num[100]={0};//首先把数组初始化为0,0代表这个人没有被移走。 
	scanf("%d,%d",&N,&M);
	int i=0;//i+1表示一个人的编号。 
	while(1){
		for(int j=0;j<M;j++){//这种方法只能一个一个传递。
			do{//拿着土豆的人要递给下一个没有被移走的人。循环是为了“跳过被移走的人”
				i=(i+1)%N;
			}while(num[i]);
		}
		num[i]=1;//把被移走的那个人标记为1
		printf("%d",i+1);//下标为i的人,他的编号是i+1 
		
		bool flag=1;//flag用来表示是否所有人被移走。1表示此时所有人都被移走。 
		for(int i=0;i<N;i++){
			if(num[i]==0){
				printf(",");//如果还有人没有被移走,那么就在后面加一个逗号。 
				flag=0;
				break;
			}
		}
		if(flag)break;
		
		do{//刚才被移走的人要递给下一个没有被移走的人。
			i=(i+1)%N;
		}while(num[i]);
	}
	return 0;
} 
//其实这才是最自然的想法:每移走一个人,他之后的人都前移一位。
#include <stdio.h>
int main(){
	int N,M;
	int num[100];
	scanf("%d,%d",&N,&M);
	for(int i=0;i<N;i++){
		num[i]=i+1;//从1开始升序初始化数组。
	}
	int i=0;
	while(N){
		i=(i+M)%N;//模加运算实现首尾相连 
		printf("%d",num[i]);
		for(int j=i;j<N-1;j++){//后面的人整体前移。 
			num[j]=num[j+1];
		}
		if(--N)printf(","); 
	}
	return 0;
} 
//用队列的思想。
#include <stdio.h>
int main(){
	int N,M;
	scanf("%d,%d",&N,&M);
	int num[101];
	for(int i=1;i<N;i++){
		num[i]=i+1;//直接把下标作为编号。每个编号为下标的元素里储存的是下一个人的编号。 
	}
	num[N]=1;//让最后一个人指向第一个人,形成队列。
	int pre=N,now=1;//now是当前元素的编号,pre是上一个元素的编号。
	while(now!=pre) {//当now=pre的时候,只剩下了一个人。
		for(int j=0;j<M;j++){//传递热土豆
			pre=now;
			now=num[pre];
		}
		printf("%d,",now);
		num[pre]=num[now];//出队
		now=num[pre];
	}
	printf("%d",now);//输出最终的幸运儿
	return 0;
} 
  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值