每日一题|医生值班问题 | 战斗!爽!

大夫值班问题

医院有A、B、C、D、E、F、G七位大夫,在一个星期内(星期一至星期天)
每天要轮流值班一天。现在已知:
A大夫比C大夫晚一天值班;
D大夫比E大夫晚两天值班;
B大夫比G大夫早三天值班;
F大夫的值班日在B和C大夫的中间,且是星期四;
请编程确定每天究竟哪位大夫值班?
**输出格式要求:"Doctor %c is on duty %s.\n"
程序运行示例如下:
Doctor E is on duty MONDAY.
Doctor B is on duty TUESDAY.
Doctor D is on duty WEDNESDAY.
Doctor F is on duty THURSDAY.
Doctor G is on duty FRIDAY.
Doctor C is on duty SATURDAY.
Doctor A is on duty SUNDAY.
 

代码

书接上回。

某个风和日丽的下午笔者正在快乐地敲着oj,突然被一道杀软题目乱了阵脚,这道赤裸裸的逻辑题被放在c语言OJ里就是出题人纯纯的恶意。
看了下网上不论是csdn还是stack overflow,都表示这是一道算法题并且最离谱的是表示“直接套七层穷尽循环就可以了”。这如同屎山一般的代码让人实在无法忍受,于是笔者愤而手搓七天七十多行代码,终于在一个晚上把这玩意儿给跑出来了。
或许我的答案不是标准答案,但是亲手解出一个难题的感觉永远无法忘怀。

老规矩,先放代码后讲解。

#include "stdio.h"
int main()
{
    int a,b,c,d,e,f,g;
    f = 3;
    char doctor[7];
    char weekday[][10] = {"MONDAY","TUESDAY","WEDNESDAY","THURSDAY","FRIDAY","SATURDAY","SUNDAY"};
    for (c = 0;c < 6;c ++)
    {
        a = c + 1;
        if (a < 3)
        {
            for (b = 4;b < 7;b ++)
            {
                g = b + 3;
                if (g > 6) g -= 7;
                for (e = 0;e < 7;e ++)
                {
                    d = e + 2;
                    if (d == 3 || e == 3) continue;
                    if (d > 6) d = e + 2 - 7;
                    if (a + b + c + d + e + f + g == 21 && b != d && e != d && e != b)
                    {
                        doctor[a] = 'A';
                        doctor[b] = 'B';
                        doctor[c] = 'C';
                        doctor[d] = 'D';
                        doctor[e] = 'E';
                        doctor[f] = 'F';
                        doctor[g] = 'G';
                        for (int i = 0;i < 7;i ++)
                        {
                            printf("Doctor %c is on duty %s.\n",doctor[i],weekday[i]);
                        }
                    }
                }
            }
        }
        if (c > 3)
        {
            a = c + 1;
            if (a == 7) a = 0;
            for (b = 0;b < 3;b ++)
            {
                g = b + 3;
                if (g == 3) continue;
                for (e = 0;e < 6;e ++)
                {
                    d = e + 2;
                    if (d == 3 || e == 3) continue;
                    if (d > 6) d = e + 2 - 7;
                    if (a + b + c + d + e + f + g == 21 && b != d && e != d && e != b)
                    {
                        doctor[a] = 'A';
                        doctor[b] = 'B';
                        doctor[c] = 'C';
                        doctor[d] = 'D';
                        doctor[e] = 'E';
                        doctor[f] = 'F';
                        doctor[g] = 'G';
                        for (int i = 0;i < 7;i ++)
                        {
                            printf("Doctor %c is on duty %s.\n",doctor[i],weekday[i]);
                        }
                    }
                }
            }
        }
    }
    return 0;
}

详细讲解

要解决这个问题,可以使用逻辑推理和编程相结合的方式。首先,根据已知条件列出一些关系,然后使用这些关系来确定每位大夫在一周内的值班日。

已知条件:

  1. F大夫的值班日是星期四。
  2. F大夫的值班日在B和C大夫的中间。
  3. B大夫比G大夫早三天值班。
  4. A大夫比C大夫晚一天值班。
  5. D大夫比E大夫晚两天值班。

首先从F大夫的值班日开始推理:

  • F大夫的值班日是星期四,所以 F = 星期四。
  • F大夫的值班日在B和C大夫的中间,所以B大夫的值班日必须在F大夫之前,C大夫的值班日必须在F大夫之后。
  • B大夫比G大夫早三天值班,因此G大夫的值班日必须在B大夫之后三天。

现在我们可以开始尝试填充一周的日期:

  • 星期四:F大夫
  • 星期三:不能是G大夫(因为G大夫在B大夫之后三天),也不能是C大夫(因为F在B和C之间),所以星期三可能是B大夫或D大夫或E大夫。
  • 星期二:不能是F大夫或C大夫,可能是B大夫(如果星期三不是B大夫的话)或D大夫或E大夫或G大夫。
  • 星期一:不能是F大夫、B大夫或C大夫,可能是D大夫或E大夫或G大夫。
  • 星期五:不能是F大夫,必须是C大夫(因为F在B和C之间)。
  • 星期六:不能是F大夫或C大夫,必须是A大夫(因为A比C晚一天)。
  • 星期日:剩下的就是G大夫。

此列需要很强的逻辑推理,各位可以自行想一下。接下来,我们采用遍历的方式,将我们的思考过程复现。

经过慎重考虑,c应为遍历的那一个。因为在该逻辑中,a与c始终深度绑定,在设想的可能性中,让c带着a遍历,而b又与c隔着f对立,因此代码遍历分为两种情况:a < 3和a > 3.

先把各个医生的值班关系导出。

a = c + 1;
g = b + 3;
d = e + 2;
//在计算的过程中,a、g、d随时有可能超出0-6的范围,要考虑其超出的的情况,从零重新开始计数。

随后以思维导图的方式画一张伪代码,导图如下。

1. 这里的a + b + c + d + e + f + g == 21是什么意思?

在对所有的可能性做遍历后,想要快速识别出其正确排序过于冗长(毕竟要使所有的变量都不想等)。因此可以先将正确的天数之和\sum_{6}^{i=0} = 21做判断,排除掉一部分选项。

2.b != d && e != d && e != b呢?

然后根据前面的分析,星期三可能是B大夫或D大夫或E大夫,但不可能同时值班。因此排除选项重复的可能性,至此基本排除了可能的重复选项。

3.如何输出?

这么简单的问题笔者甚至想了很长时间...

由答案看结果,星期是按照顺序输出的,直接在遍历中将weekday输出即可。已经确定了天数的a,b,c,d,e,f,g小可爱们,在开头重新定义一个数组doctor,将排好的天数作为数组下标,逐一分配给医生A-G即可。

over。

战斗!爽!(

  • 27
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值