前言:
题目链接
进入链接后,点击实践项目,以下题目为6.8.17到6.8.20,
古老的纸牌游戏
任务描述:
本题所述的麻将纸牌只包括3大类别的牌:条、饼、万(不包括老千、红花和白花)。每大类的牌点数都有从1至9,共27种牌,每种牌有4张,一副牌只取108张。
和牌规则:
5张牌和(音:胡)牌的规则如下:
1.必须有一个对子,即两张相同的牌,称为“掌”,比如:两个2饼做掌,两个4条做掌等。
2.剩余的3张牌,如果正好形成“哈子”(3个一样的牌,如3个2饼,麻将中称为一刻)或者“一趟副”(同种类点数连续,如1条、2条、3条),就可以和牌了。
3.输入的牌肯定是4张。
4.条用T表示,饼用B表示,万用W表示。
也可以理解为和牌类型有以下几种(11表示一对,123表示一副、111表示一刻):
(1)11、123(1副1对)
(2)11、111(1哈1对)
假设你手中有4张牌,如果加上别人打出手的1张牌或你自己再摸1张牌,就构成和牌,则称“有叫儿”(麻将称为听牌)。
给你4张牌,你知道自己是否“有叫儿”并和什么牌吗?
输入格式:
输入共一行,代表一组数据(一手牌)。
在一行中包含以1个空格分隔的4个数据,每个数据由1个数字加1个大写字母构成,代表1张纸牌,4个数据代表一手牌。(例如:1T代表1条、2W代表2万、9B代表9饼)。
输出格式:
该组数据如果“有叫儿”,则依次输出可以和的牌(叫儿),如果有多个“叫儿”,按“条、饼、万”的顺序输出,同一种类的牌,按点数从小到大输出,每个“叫儿”之后输出一个圆点句号。
该组数据如果“没有叫儿”,则输出:No jiaor。
输入样例(平和2张):
4B 4B 3T 4T
输出样例:
2T.5T.
输入样例(和对倒2张):
1T 6W 6W 1T
输出样例:
1T.6W.
输入样例:(和边张)
1T 2T 6B 6B
输出样例:
3T.
输入样例(和卡):
4T 2T 6W 6W
输出样例:
3T.
输入样例(和单吊1张):
4T 2T 6W 3T
输出样例:
6W.
输入样例(和单吊或和卡):
4T 2T 3T 3T
输出样例:
3T.
输入样例(平和、单吊):
4T 4T 4T 3T
输出样例:
2T.3T.5T.
输入样例(没和):
4T 4T 4T 4T
输出样例:
No jiaor
输入样例(没和):
4T 4T 4W 8B
输出样例:
No jiaor
解题思路:
还记得上次写扑克,这次是写麻将,麻将的规则比起扑克要麻烦一些,从题目给出了很多的样例也可以看出
-
使用结构体对麻将卡牌进行拆分
-
输出是要按牌型排序的,用一个数组type存储牌型,用序号表示优先级
-
记住一副牌里一种卡牌只有四张,如果手上卡牌4张一样的话是没法有叫儿的
-
可以分析一下,一共有4张牌,对于牌型,若三种牌型卡牌分布为1 1 2是不可能有叫儿的,
-
不论顺序,要有叫儿的话,只有三种牌型分布4 0 0,2 2 0,3 1 0
-
先分析4 0 0的情况,也就是手上4张牌牌型一样,这种是情况最复杂的,按我写的代码的思路按顺序说情况,
先是4张牌点数连一起,那可以和的牌只有牌只有两张,中间的不能动,与最小点数或最大点数凑成对子
三张牌点数连一起,以实例展示吧,比如4T 2T 3T 3T,这种情况只能再给一张与那张对子一样的牌,还有就是4T 2T 3T 7T,与剩下那张凑个对子
三张卡牌相同,那就要判断剩下那张卡牌与这三张的点数关系,还要判断边界关系,比如 1T 2T 2T 2T,这种卡在边界的,就只有两种,一种自身,还有组成一个顺子,不在边界且差为1,比如4T 4T 4T 3T,除了自身,还可以组两种顺子,还有差为2的,比如4T 4T 4T 2T,一种自身,一种顺子,当差大于2时,就只有自身了 -
3 1 0的情况,只有那三张牌凑成了顺子或一样的,才行,只有一种就剩下那张牌再来一张才能和
-
2 2 0的情况,只有两两为对子或一为对子,另两张点数相连才行,若为对子就输出对子的牌,注意按从小到大输出,有对子就只能凑对子了
参考代码:
#include<stdio.h>
char type[3] = {'T', 'B', 'W'};//表示牌型优先级
struct node {
char model;//牌型
int number[10];//存储该牌型对应的点数的牌,比如若有点数为1的牌,则number[1]++
int flag;//表示在该牌型有几张牌
} card[3];//三种牌型
void print() {//没有叫儿
printf("No jiaor");
}
void flag_1() {//处理当其他三张牌凑成了顺子或一样时的情况,且牌型与那三张牌不同
for (int i = 0; i < 3; i++) {
if (card[i].flag == 1) {
for (int j = 1; j <= 9; j++) {
if (card[i].number[j]) {//找出那张牌,再给一张一样的牌就是一个对子,就和了
printf("%d%c.", j, card[i].model);
return;
}
}
}
}
}
int same_card(int i) {//三张牌凑成了顺子或一样的
for (int j = 1; j <= 7; j++) {
if ((card[i].number[j] && card[i].number[j + 1] && card[i].number[j + 2]) || card[i].number[j] == 3) {
flag_1();
return 1;
}
}
return 0;
}
int Straight(int i)//4张卡牌顺子
{
for(int j=1;j<=6;j++)
{
if(card[i].number[j] && card[i].number[j + 1] && card[i].number[j + 2]&&card[i].number[j + 3])
{
printf("%d%c.%d%c.",j,card[i].model,j+3,card[i].model);
return 1;
}
}
return 0;
}
int _Straight(int i)//三张顺
{
int vis[10]={0};
int j;
for(j=1;j<=7;j++)
{
if((card[i].number[j] && card[i].number[j + 1] && card[i].number[j + 2]))
{
vis[j]=vis[j+1]=vis[j+2]=1;
break;
}
}
if(j==8)//j==8意味着没有顺子
return 0;
for(j=1;j<=9;j++)
{
if(vis[j]&&card[i].number[j]==2)//情况例:4T 2T 3T 3T
{
printf("%d%c.", j, card[i].model);
return 1;
}
if(!vis[j]&&card[i].number[j])
{
printf("%d%c.", j, card[i].model);
return 1;
}
}
return 0;
}
void same_card_4(int i,int j)
{
int k;
for(k=1;k<j;k++)
{
if(card[i].number[k])
{
break;
}
}
if(k<j)
{
if(j-k==1)//情况例:4T 4T 4T 3T
{
if(k>1)
printf("%d%c.",k-1,card[i].model);
printf("%d%c.",k,card[i].model);
printf("%d%c.",k+2,card[i].model);
return;
}
else if(j-k==2)//情况例:4T 4T 4T 2T
{
printf("%d%c.",k,card[i].model);
printf("%d%c.",k+1,card[i].model);
return;
}
printf("%d%c.",k,card[i].model);//差大于2
return;
}
for(k=j+1;k<=9;k++)
{
if(card[i].number[k])
{
break;
}
}
if(k<=9)
{
if(k-j==1)//情况例:4T 4T 4T 3T
{
printf("%d%c.",k-2,card[i].model);
printf("%d%c.",k,card[i].model);
if(k<9)
printf("%d%c.",k+1,card[i].model);
return;
}
else if(j-k==2)//情况例:4T 4T 4T 2T
{
printf("%d%c.",k-1,card[i].model);
printf("%d%c.",k,card[i].model);
return;
}
printf("%d%c.",k,card[i].model);//差大于2
return;
}
}
void flag_2()
{
int count=0;
int number_2[2];
int Pairs[2]={0};
int count_i;
int Pairs_i;
for(int i=0;i<3;i++)
{
if(card[i].flag==2)
{
for(int j=1;j<=9;j++)
{
if(card[i].number[j]==2)
{
number_2[count++]=j;
if(count==2)
{
printf("%d%c.",number_2[0],card[count_i].model);
printf("%d%c.",number_2[1],card[i].model);
return;
}
count_i=i;
break;
}
else if(j<9&&card[i].number[j]&&card[i].number[j+1])
{
if(j>1)
Pairs[0]=j-1;
if(j<8)
Pairs[1]=j+2;
Pairs_i=i;
break;
}
else if(j<8&&card[i].number[j]&&card[i].number[j+2])
{
Pairs[0]=j+1;
Pairs_i=i;
break;
}
}
}
}
if(count==1)
{
if(Pairs[0])
printf("%d%c.",Pairs[0],card[Pairs_i].model);
if(Pairs[1])
printf("%d%c.",Pairs[1],card[Pairs_i].model);
if(!(Pairs[0]||Pairs[1]))
print();
return;
}
print();
}
void solve() {
for (int i = 0; i < 3; i++) {
if (card[i].flag == 4) {
if(Straight(i))
return;
if(_Straight(i))
return;
for(int j=1;j<=9;j++)
{
if(card[i].number[j]==3)//三张卡牌相同
{
same_card_4(i,j);//传入j,从j开始往两头找剩下那张牌,也便于判断剩下那张牌与这三张卡牌的点数关系
return;
}
}
}
if (card[i].flag == 3) {
if(!same_card(i))
{
print();
}
return;
}
}
flag_2();
}
int main() {
for (int i = 0; i < 3; i++)
card[i].model = type[i];
char model;
int number;
while (~scanf("%d%c", &number, &model)) {//获取输入的卡牌
for (int i = 0; i < 3; i++) {
if (card[i].model == model) {
card[i].number[number]++;
if (card[i].number[number] == 4) {//当有4张卡牌一样时,则不可能有叫儿
print();
return 0;
}
card[i].flag++;
break;
}
}
}
solve();
return 0;
}
餐饮服务质量调查打分
任务描述
在商业和科学研究中,人们经常需要对数据进行分析并将结果以直方图的形式显示出来,这会大大增加这些数据的直观性,也便于数据的分析与对比。下面以顾客对餐饮服务打分为例,输入一个正整数repeat (0<repeat<10),做repeat次下列运算:
输入一个正整数n(1≤n≤20),表示有n个学生被邀请来给自助餐厅的食品和服务质量打分,分数划分为1~5这5个等级(1表示最低分,5表示最高分),试统计调查结果,并用*打印出如下形式的统计结果直方图。
输入格式:
第1个整数repeat为数据组数,一共有repeat组数据,请分别处理每组数据,每组数据输出一个直方图。
接下来为repeat组数据,每组数据的第1个数为打分人数n,接下来为这n个人的n个打分。
输出格式:
按输出样例的样式输出结果。
输入样例:
1
10
1 2 2 3 3 5 2 2 3 5
输出样例:
*
* *
* * *
* * * *
1 2 3 4 5
输入样例:
2
10
1 1 1 1 1 2 3 4 5 5
20
1 1 1 2 2 2 3 3 3 4 5 1 2 3 4 2 2 3 5 2
输出样例:
*
*
*
* *
* * * * *
1 2 3 4 5
*
*
* *
* * *
* * *
* * * * *
* * * * *
1 2 3 4 5
解题思路:
这题比起前面的纸牌游戏就简单不少了,就是画图
- 仍然是用结构体处理,number和score像构成了坐标一样,嘿嘿
参考代码:
#include<stdio.h>
struct node
{
int number;//打该分的人数
int score;//分数
}student[6];
int max=0;//打分最多,也就是图里的最高纵坐标
void solve()
{
for(int i=max;i>0;i--)
{
int flag=0;//统计图中空的地方
int t=0;
for(int j=1;j<=5;j++)
{
if(student[j].number>=i)
{
for(int i=0;i<flag;i++)
{
printf(" ");
}
flag=0;
if(t)
printf(" ");
printf("*");
t++;
}
else
flag++;
}
printf("\n");
}
}
int main()
{
int repeat;
scanf("%d",&repeat);
int n,a;
for(int i=1;i<=5;i++)
{
student[i].score=i;
}
while(repeat--)
{
scanf("%d",&n);
for(int i=1;i<=5;i++)
student[i].number=0;
for(int i=0;i<n;i++)
{
scanf("%d",&a);
for(int j=1;j<=5;j++)
{
if(a==student[j].score)
{
student[j].number++;
if(max<student[j].number)
max=student[j].number;
break;
}
}
}
solve();
printf("1 2 3 4 5\n");
}
return 0;
}
月历
任务描述
X想知道某年某月的日历,你能为他编程输出吗?
输入格式:
输入一行,两个正整数,分别代表年份和月份。
输出格式:
严格按样例格式输出一个月的日历。
第1行输出月份简称和年份,中间有个圆点和空格。
第2行输出表头,为星期一至星期日的缩写,每个单词之间一个空格。
第3行为28个减号。
接下来的几行是日历内容,每个日期输出时占3列,日期前后之间再加1个空格,保证与相对应的星期名称右对齐。
输入样例:
2019 9
输出样例:
SEP. 2019
Mon Tue Wed Thu Fri Sat Sun
---------------------------
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
提示
重要提示:1900年1月1日是星期一。
星期一:Monday 缩写:Mon.
星期二:Tuesday 缩写:Tue.
星期三:Wednesday 缩写:Wed.
星期四:Thursday 缩写:Thu.
星期五:Friday 缩写:Fri.
星期六:Saturday 缩写:Sat.
星期日:Sunday 缩写:Sun.
一月份JAN.
二月份FEB.
三月份MAR.
四月份APR.
五月份MAY.
六月份JUN.
七月份JUL.
八月份AUG.
九月份SEP.
十月份OCT.
十一月份NOV.
十二月份DEC.
解题思路:
还是画图,不过这个感觉有意思些,
不过我一开始没有看到提示里的1900年1月1日是星期一。用了蔡勒公式
蔡勒公式:
int h = (day + 2 * month + 3 * (month + 1) / 5 + year + year / 4 - year / 100 + year / 400 + 1) % 7;
day为日,month为月份,year为年份
h的值是几,即为星期几,
为0时,星期天
参考代码:
使用蔡勒公式版:
//请在此输入你的代码,复杂程序可先在Dev C++中运行调试后再提交
#include<stdio.h>
void print_month(int year,int month)
{
switch(month)
{
case 1:
printf("JAN. ");
break;
case 2:
printf("FEB. ");
break;
case 3:
printf("MAR. ");
break;
case 4:
printf("APR. ");
break;
case 5:
printf("MAY. ");
break;
case 6:
printf("JUN. ");
break;
case 7:
printf("JUL. ");
break;
case 8:
printf("AUG. ");
break;
case 9:
printf("SEP. ");
break;
case 10:
printf("OCT. ");
break;
case 11:
printf("NOV. ");
break;
case 12:
printf("DEC. ");
break;
}
printf("%d\n",year);
}
void print_week()
{
printf("Mon Tue Wed Thu Fri Sat Sun\n");
}
int getWeek(int year,int month,int day)//蔡勒公式
{
if(month<3)//如果给定日期在1月或2月(即month1为1或2),则需要将年份减1,将月份增加12。这是为了将这两个月视为前一年的13月和14月
{
month+=12;
year--;
}
//int h=(sun+(13*(month1+1)/5)+year%100+(year%100/4)+(year/400)-2*(year/100))%7;
int h=(day+2*month+3*(month+1)/5+year+year/4-year/100+year/400+1)%7;
return h;
}
int main()
{
int year,month;
scanf("%d%d",&year,&month);
print_month(year,month);
print_week();
for(int i=0;i<27;i++)
printf("-");
printf("\n");
int k=year%100?year%4?0:1:year%400?0:1;
int m[13]={0,31,28+k,31,30,31,30,31,31,30,31,30,31};
int h=getWeek(year,month,1);
int count=h;
if(h==0)
{
for(int i=0;i<6;i++)
printf(" ");
count=7;
}
for(int i=1;i<h;i++)
printf(" ");
int t=0;
for(int i=1;i<=m[month];i++)
{
if(t)
printf(" ");
printf("%3d",i);
t++;
if(count==7)
{
printf("\n");
count=0;
t=0;
}
count++;
}
return 0;
}
利用题目中的提示:
//请在此输入你的代码,复杂程序可先在Dev C++中运行调试后再提交
#include<stdio.h>
void print_month(int year,int month)
{
switch(month)
{
case 1:
printf("JAN. ");
break;
case 2:
printf("FEB. ");
break;
case 3:
printf("MAR. ");
break;
case 4:
printf("APR. ");
break;
case 5:
printf("MAY. ");
break;
case 6:
printf("JUN. ");
break;
case 7:
printf("JUL. ");
break;
case 8:
printf("AUG. ");
break;
case 9:
printf("SEP. ");
break;
case 10:
printf("OCT. ");
break;
case 11:
printf("NOV. ");
break;
case 12:
printf("DEC. ");
break;
}
printf("%d\n",year);
}
void print_week()
{
printf("Mon Tue Wed Thu Fri Sat Sun\n");
}
int getWeek(int year,int month,int day)//蔡勒公式
{
if(month<3)//如果给定日期在1月或2月(即month1为1或2),则需要将年份减1,将月份增加12。这是为了将这两个月视为前一年的13月和14月
{
month+=12;
year--;
}
//int h=(sun+(13*(month1+1)/5)+year%100+(year%100/4)+(year/400)-2*(year/100))%7;
int h=(day+2*month+3*(month+1)/5+year+year/4-year/100+year/400+1)%7;
return h;
}
int fun(int year)//获取从1900到输入的年份的天数
{
int days=0;
for (int a = 1900; a < year; a++)
{
if (a % 400 == 0 || a % 4 == 0 && a % 100 != 0)
{
days+=366;
}
else
days+=365;
}
return days;
}
int funweek(int year,int days)//判断星期几
{
days+=fun(year);//总天数
int h=days%7;
return h;
}
int main()
{
int year,month;
scanf("%d%d",&year,&month);
print_month(year,month);
print_week();
for(int i=0;i<27;i++)
printf("-");
printf("\n");
int k=year%100?year%4?0:1:year%400?0:1;
int m[13]={0,31,28+k,31,30,31,30,31,31,30,31,30,31};
//int h=getWeek(year,month,1);
int days=1;
for(int i=1;i<month;i++)
{
days+=m[i];
}
int h=funweek(year,days);
int count=h;
if(h==0)
{
for(int i=0;i<6;i++)
printf(" ");
count=7;
}
for(int i=1;i<h;i++)
printf(" ");
int t=0;
for(int i=1;i<=m[month];i++)
{
if(t)
printf(" ");
printf("%3d",i);
t++;
if(count==7)
{
printf("\n");
count=0;
t=0;
}
count++;
}
return 0;
}
鲜花数
任务描述
鲜花数是指一个N位正整数(7≥N≥3),它的每个位上的数字的N次幂之和等于它本身。
例如:
153=13+53+33 ,1634=14+64+34+44 。
当N=3时,花朵数又称为水仙花数;
当N=4时,花朵数又称为四叶玫瑰数;
当N=5时,花朵数又称为五角星数;
当N=6时,花朵数又称为六合数;
当N=7时,花朵数又称为北斗数,等等。
要求编写程序,输出所有N位花朵数。
输入格式:
一个整数N(7≥N≥3)
输出格式:
从小到大输出所有N位鲜花数,一个数一行。
输入样例:
3
输出样例:
153
370
371
407
输入样例:
4
输出样例:
1634
8208
9474
解题思路:
这题没什么好说的,就是N为几,就去遍历10N-1到10N的数,就是拓展了下那道经典的水仙花的题目
参考代码:
#include <stdio.h>
#include <math.h>
// 函数声明,
int isFlower(int number, int N);
void findFlower(int N);
int main() {
int N;
scanf("%d", &N);
findFlower(N);
return 0;
}
// 检查一个数是否为鲜花数
int isFlower(int number, int N) {
int originalNumber = number;
int sum = 0;
while (number > 0) {
int digit = number % 10;
sum += pow(digit, N);
number /= 10;
}
return sum == originalNumber;
}
// 找到并打印所有N位鲜花数
void findFlower(int N) {
int lower = pow(10, N - 1);
int upper = pow(10, N);
for (int i = lower; i < upper; i++) {
if (isFlower(i, N)) {
printf("%d\n", i);
}
}
}