PTA 综合3 值班安排(c语言)

文章介绍了一个使用C语言编写的程序,该程序根据输入的一系列条件来确定大夫每周的值班顺序。程序通过遍历所有可能的医生排列组合,结合条件判断函数检查是否满足输入的约束,最终输出满足条件的值班序列。输入包括大夫之间的相对值班顺序和特定大夫的值班天数。程序的核心在于遍历和判断算法,但作者认为其效率不高,期待更优解法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目如下:

医院有A、B、C、D、E、F、G 7位大夫,在一星期内(星期一至星期天)每人要轮流值班一天,如果已知:
(1)A大夫比C大夫晚1天值班;
(2)D大夫比E大夫晚1天值班;
(3)E大夫比B大夫早2天值班
(4)B大夫比G大夫早4天值班;
(5)F大夫比B大夫晚1天值班;
(6)F大夫比C大夫早1天值班;
(7)F大夫星期四值班。
就可以确定周一至周日的值班人员分别为:E、D、B、F、C、A、G。
编写程序,根据输入的条件,输出星期一至星期天的值班人员。

输入格式:

先输入一个整数n,再输入n组条件,要求能够根据输入的条件确定唯一的值班表,且输入的n组条件中能够直接或间接得到任意两位大夫的关联关系,例如上面的条件(2)直接显示了D与E间的关系,而通过条件(1)、(6)、(5)可以间接得到A与B的关系。
条件的输入格式有2种:
格式1:编号 比较运算符 编号 天数
其中比较运算符有2种:> 或 < ,分别表示“早”或“晚”
例如:A<C1 表示:A大夫比C大夫晚1天值班
格式2:编号 = 数值
例如:F=4 表示:F大夫在星期四值班

输出格式:

输出周一至周日的值班序列。

输入样例:

7
A<C1
D<E1
E>B2
B>G4
F<B1
F>C1
F=4

输出样例:

EDBFCAG

         话不多说,咱们直接上代码。具体的含义都已经写在代码里面,但是本人始终觉得这个代码的算法过于笨重,如果有更好的算法,希望大佬能够贡献出来!!

        本人也是一个才开始学习c的小白,整理这个希望能得到指点,希望帮助一些没思路的同学,也希望更多的大佬帮助我们这些小白!!!

#include<stdio.h>
#define DAY 7       //定义日期为一周七天.

struct content {    //创建一个结构体存储输入的数据.
	char early;
	char late;
	int cdate;
} beduty[10];


int judge(int *a, int n);   //用来判断任意生成的值班安排是否符合题目要求.
int hunluan(int *a);        //用来判断生成的值班安排是否是正确的.
                            //(正确的首要要求是每个人合理分配至七天.

int main() {
	int n, i = 0, a[DAY];
	int A, B, C, D, E, F, G;
	char  ch,s[5];
	scanf("%d", &n);     //读取第一行n.
	ch=getchar();        //用getchgar()将键入的'\n'读取.
	for (; i < n; i++) { //这个循环开始读取下面的数据.
		gets(s);
		if (s[1] == '>') {
			beduty[i].early = s[0];
			beduty[i].late = s[2];
			beduty[i].cdate = s[3] - 48;
		} else if (s[1] == '<') {         //为了统一,我们以'>'为存储标准,'>'前为值班早的医
			beduty[i].early = s[2];       //生,如果是'<',则将读到s[0]存至late中,s[2]存至
			beduty[i].late = s[0];        //early中。如果是'=',则rly与late存储为同一值,
			beduty[i].cdate = s[3] - 48;  //最后的时间差都存储在cdate中.
		} else if (s[1] == '=') {
			beduty[i].early = beduty[i].late = s[0];
			beduty[i].cdate = s[2] - 48;
		}
	}
//这里就是任意生成值班安排 数组a[7],数字1234567分别代表ABCDEFG七个医生,在a[0]-a[6]的排列就表
//示值班,比如题目的EDBFCAG,在数组中从a[0]-a[6]按照5426317的顺序存储在a数组之中,这里就是任意生
//成这样的数组,前面的hunluan和judge就是判断生成的数组是否满足条件.
	for (A = 1; A <= 7; A++) {
		for (B = 1; B <= 7; B++) {
			if(B==A) B++;
			for (C = 1; C <= 7; C++) {
				if(C==B||C==A) C++;
				for (D = 1; D <= 7; D++) {
					if(D==C||D==B||D==A) D++;
					for (E = 1; E <= 7; E++) {
						if(E==D||E==C||E==B||E==A) E++;
						for (F = 1; F <= 7; F++) {
							if(F==E||F==D||F==C||F==B||F==A) F++;
							for (G = 1; G <= 7; G++) {
								if(G==F||G==E||G==D||G==C||G==B||G==A) G++;
								a[0] = A;
								a[1] = B;
								a[2] = C;
								a[3] = D;
								a[4] = E;
								a[5] = F;
								a[6] = G;
								if(hunluan(a)){
									if (judge(a, n)) goto E; //如果满足条件则直接goto输出.
								}
							}
						}
					}
				}
			}
		}
	}
	E:
	for (i = 0; i < 7; i++) {
		printf("%c", a[i] + 64);    //a中存储的是数字1代表A,所以输出时将数字+64;或者+'A'-1.
  }
	return 0;
}
//下面便是判断是否满足值班的条件的judge语句,满足输出1,反之输出0.


int judge(int *a, int n) {
	int i = 0;
	for (; i < n; i++) {
		if (beduty[i].early == beduty[i].late) {    //early==late说明这个条件是'F=4'。
            //下面的语句,如果a[beduty[i].cdate-1]的值不等于存储的值,则不满足,返回0.
			if (!(a[beduty[i].cdate - 1] == (int)(beduty[i].early - 64))) return 0;
		} else {
            //第二种值班先后的输入方式.我们在存储的时候,无论先后我们都将早值班的医生存在early中.
            //因此我们只需要先找到early中的医生在a数组中的位置,再跟晚cdate时间后的a数组中存储的
            //医生代号比较,如果不相等则返回0.如果a满足条件则输出1.
			for (int j = 0; j < DAY; j++) {
				if (a[j] == (beduty[i].early - 64)) {
					if (!(a[j + beduty[i].cdate] == beduty[i].late-64)) return 0;
					else break;
				}
			}
		}
	}
	return 1;
}

int hunluan(int *a){        //这个判断数组a中是否存在重复的医生代号,这一步很关键.
	int i,j;                //如果没有这个判断,首先程序会执行很多次的judge,其次存在很多有重复
	for(i=0;i<7;i++){       //的排列满足条件.例如‘6666666’,也就是'FFFFFFF',在judge时会返回1.
		for(j=i+1;j<7;j++){ //因为judge对这个数组不会进行return 0;的任何反馈.
			if(a[i]==a[j]) return 0;
		}
	}
	return 1;
}

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

没烦恼__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值