杭高OJ-1273 米塞莉娜的生日1

题目来源

(为方便起见,本题解中用带引号“月”表示某月如1月,带引号“日”表示某日如1日,不带引号日期表示具体日期如1月1日)

这是一道推理题目,要求在一些给定的日期里面找出符合条件的日期。要想解出这道题,首要的不是编程能力,而是推理能力。解出这道题的关键,就是要理解那段奇怪的对话:

A:我不知道她的生日。
B:我知道你不知道她的生日,我也不知道。
A:现在我知道了。
B:我也知道了。

再看给出的样例数据:

7月 1日、3日、8日

8月 2日、3日、6日、7日

9月 1日、8日、10日

10月 4日、5日、6日、9日

11月 5日

想象一下,如果那个日期是11月5日会怎么样?A被告知了“月”,即11月,而选项中满足“月”是11月的,只有11月5日一个日期,那么A将会直接说出“我知道她的生日是11月5日”,而不会说“不知道”。因此,A被告知的“月”肯定不是只出现一次的11月。换句话说,你的第一步就是要排除所有只出现一次的日期。

现在已经排除了11月5日,继续第二步:B说“我知道你不知道她的生日,我也不知道”。这句话是整个程序的关键。B是被告知“日”的,他为什么会仅凭“日”推断出A猜不出来呢?一定是这个“日”对应的所有日期都不能让A仅凭“月”推出来。这样,第一步排除了11月5日,那么第二步就要排除所有5日(因为B只知道5日的情况下不可能排除“11月5日”这个能让A直接推出的选项)。因此,前半句的要求就是排除所有与第一步排除的日期同“日”的日期(通俗的讲,第一步排除了1月1日,那么第二步排除所有1日;第一步排除了11月5日,那么第二步排除所有5日)。后半句类似于第一步,排除只出现一次的2、4、7、9、10日。

让我们看一下现在的情况(加粗表示尚未被排除):

7月 1日、3日、8日

8月 2日、3日、6日、7日

9月 1日、8日、10日

10月 4日、5日、6日、9日

11月 5日

在这时,只知道“月”的A却说他也知道了。那么,符合条件的日期在剩下来的日期里面一定是“月”只出现一次的日期。查表,显然符合条件的只有一个:10月6日。

看似只要分析前三句就可以推理出正确结果,实则远没有那么简单。请看下面的例子:

1月 1日、2日、4日、7日

2月 1日

3月 1日、4日、5日

4月 6日、7日

5月 4日、6日

6月 1日、7日

7月 3日、4日

如果还是按照上面的方法来做,你会得到三个答案:3月4日、6月7日和7月4日。难道这题目有三个解吗?绝不可能。这时候就需要分析最后一句话:B说的“我也知道了”,这意味着类似于第三步A能根据“月”推出来,B也能根据“日”推出来。如果是3.4或7.4,B仅凭“日”是推不出来的。只有6月7日,满足两人都能推出来的要求。

整理一下:

第一步,排除所有“月”只对应一个日期的日期

第二步,排除第一步排除的日期同“日”的日期,以及所有“日”只对应一个日期的日期

第三步,选出未被排除的日期里面“月”只对应一个日期的日期

第四步,在第三步选出的日期里面找出那个“日”只出现一次的日期

那么程序就很简单了。首先,创建一个13*32的列表表示日历(第一行和第一列存储每个“月”和“日”的次数),存储所有的选项日期,代码如下:

c=[[0 for i in range(32)]for j in range(13)]
n=int(input())
for i in range(n):
    a,b=map(int,input().split())
    c[a][b]+=2
    c[0][b]+=1
    c[a][0]+=1

第一、二步代码如下:

lst=[]
for q in range(1,13):
    if c[q][0]==1:
        lst.append(q)
for i in lst:
    k=c[i].index(2)
    c[i][0]=0
    c[i][k]=0
    c[0][k]-=1
    for j in range(13):
        if c[j][k]==2:
            c[j][k]=0
            c[j][0]-=1
            c[0][k]-=1
for i in range(1,32):
    if c[0][i]==1:
        for j in range(1,13):
            if c[j][i]==2:
                c[j][i]=0
                c[0][i]=0
                c[j][0]-=1

第三步代码如下:

for i in range(1,13):
    if c[i][0]==1:
        k=c[i].index(2)
        c[i][k]=3

第四步代码如下:

a=0
b=0
res=[]
for i in range(1,32):
    cnt=0
    for j in range(1,13):
        if c[j][i]==3:
            a,b=j,i
            cnt+=1
    if cnt==1:
        print(a,b)
        exit(0)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值