题目如下:
医院有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;
}