一周一篇之one

问题描述:

VOS声控开关是一种很灵活的小设备,它的一边是插头,可以插到插座里;另一边是一个插座可以插一盏灯或者另一个VOS开关。

当VOS开关接通之后,它从插头获取电能,同时可以输出到插座里。当你打响指的时候 – 发出嗒声-- 通了电的VOS开关会在‘接通’和‘关闭’之间切换。

抱着通过一个奇点来毁灭整个宇宙的希望,我买了 N 个VOS开关,把它串了起来,第一个开关插入插座,第二个开关插到第一个VOS开关的插座上,以此类推。另有一盏灯插在第 N 个VOS开关上。

刚开始的时候,所有的开关都是关闭状态,所以此时只有第一个开关是通电的,而灯是不亮的。我打了一个响指之后,第一个开关被接通,第二个开关通电了并保持关闭状态。再打一次响指,触发两个VOS开关,第二个开关失去了电能,但是它已是开通状态。第三次响指之后,第一个VOS开关接通,给第二个开关通电。此时,两个VOS开关都是开通状态,如果有一个灯插在第二个开关上,那么它就被点亮了。

我就这样做了几个小时之后,在打了 K 次响指之后,最后的灯是点亮的,还是不亮的?灯只在它插在通电的VOS开关上才会被点亮。

输入:

输入的第一行表示测试用例的个数 T。之后的T行,每一行都包括两个整数, N 和 K。

输出:

针对每个测试用例,输出必须形如:'Case #x: y',其中 x 表示用例的需要(从1开始计数),而y 则要么是 ‘ON’ 要么是 ‘OFF’,表示电灯泡的状态。

 

Limits

1 ≤ T ≤ 10,000.

Small dataset

 

1 ≤ N ≤ 10;

0 ≤ K ≤ 100;

Large dataset

 

1 ≤ N ≤ 30;

0 ≤ K ≤ 108;

Sample

Input

4

1 0

1 1

4 0

4 47

Output

Case #1: OFF

Case #2: ON

Case #3: OFF

Case #4: ON

 

首先,针对问题进行分析:

通过对题目的分析,我们可以基本得出结论:

当且仅当所有的开关均是闭合状态,指示灯亮。于是我们可以在每次响指后,判断所有开关的闭合状态,从而得出指示灯的状态。

代码实现如下(python 语言):说明代码实现需要将输入文件的第一行去掉。

#!/usr/bin/python
# -*- coding:utf-8 -*-
import string

def compute_result(switch_num, action_num):
    #init all the switch state in state_list
    state_list = list()
    for i in range(switch_num):
        state_list.append(0)
    #update state_list after action
    for i in range(action_num):
        connect_num = 1
        for state in state_list:
            if state == 1:
                connect_num += 1
            else:
                break
        if connect_num > len(state_list):
            connect_num = len(state_list)
        for k in range(connect_num):
            if state_list[k] == 1:
                state_list[k] = 0
            else:
                state_list[k] = 1
    #compute result
    if 0 not in state_list:
        return "ON"
    return "OFF"

if __name__ == "__main__":
    k = 1
    out_result = ""
    input_file = "Chain.large.1496809484823.input.txt"
    with open (input_file, "r") as fread:
        for line in fread.readlines():
            switch_num, action_num = line.split(" ")
            print switch_num, action_num
            result = compute_result(string.atoi(switch_num), string.atoi(action_num))
            out_result += "Case #%s: %s\n" % (k, result)
            k += 1
    # write result to out file
    with open("%s_output.txt" % input_file, "w") as fwrite:
        fwrite.write(out_result)

运行发现,如果运行大数据,比如响指次数达几千万次,将耗时很多,大概计算了下如果有一万组数据,就会耗时多大几十个小时。

优化1: 观察到第一个开关始终是通电的,那如果响指次数为偶数的话,第一个开关应该是打开的,那么指示灯一定是不亮的,那么优化的代码加了一句:

#!/usr/bin/python
# -*- coding:utf-8 -*-
import string

def compute_result(switch_num, action_num):
    if action_num % 2 == 0:
        return "OFF"
    #init all the switch state in state_list
    state_list = list()
    for i in range(switch_num):
        state_list.append(0)
    #update state_list after action
    for i in range(action_num):
        connect_num = 1
        for state in state_list:
            if state == 1:
                connect_num += 1
            else:
                break
        if connect_num > len(state_list):
            connect_num = len(state_list)
        for k in range(connect_num):
            if state_list[k] == 1:
                state_list[k] = 0
            else:
                state_list[k] = 1
    #compute result
    if 0 not in state_list:
        return "ON"
    return "OFF"

if __name__ == "__main__":
    k = 1
    out_result = ""
    input_file = "Chain.large.1496809484823.input.txt"
    with open (input_file, "r") as fread:
        for line in fread.readlines():
            switch_num, action_num = line.split(" ")
            print switch_num, action_num
            result = compute_result(string.atoi(switch_num), string.atoi(action_num))
            out_result += "Case #%s: %s\n" % (k, result)
            k += 1
    # write result to out file
    with open("%s_output.txt" % input_file, "w") as fwrite:
        fwrite.write(out_result)

这样运行之后,确实响指偶数确实很快返回了结果,但是理论上只会缩短一半的时间,耗时仍然比较长。

那有没有更加有效的方法呢?下面我们就来仔细分析下。

以两个开关为例,分析过程如下图(要特别注意的一点是问题描述中着重说明了通了电的开关会在‘接通’和‘关闭’之间切换):


说明:0 代表初始状态, 1,2,…代表第i次响指后的状态。红线代表通电。

结论:两个开关,最少需要3次响指,指示灯才会亮, 第4次响指后开关恢复初始状态

所以两个开关的情况下使得指示灯亮的响指次数为3,7,11,15……,最少响指次数为3

下面,同样分析三个开关的情况,如下图过程:

结论:三个开关需要7次响指才会使得指示灯亮,第8次响指后开关恢复初始状态。

所以三个开关的情况下使得指示灯亮的响指次数为7,15,23,31,….,最少响指次数为7次。

总结如下表

开关个数

使得指示灯亮的最少响指次数

使得指示灯亮的响指次数

1

1

1, 3, 5, 7….

2

3

3, 7, 11, 15, ….

3

7

7, 15, 23, 31, …

4

15(24-1或者2*7+1

15, 31, 47, 63, …

…..

N

M=2N-1或者2*(N-1开关的值)+1

M或者M+2N M+2N+1 ……

优化2:代码实现如下:

#!/usr/bin/python
# -*- coding:utf-8 -*-
import string
import math
def compute_result(switch_num, action_num, result):
    if action_num % 2 == 0:
        return "OFF"
    if action_num < result[switch_num]:
        return "OFF"
    elif action_num == result[switch_num]:
        return "ON"
    else:
        if action_num % (math.pow(2, switch_num)) == result[switch_num]:
            return "ON"
        return "OFF"

def compute_min_num():
    result = dict()
    min_num = 1
    for i in range(1,500):
        result[i] = min_num
        min_num = min_num * 2 + 1
    return result

if __name__ == "__main__":
    k = 1
    out_result = ""
    result1 = compute_min_num()
    print "result= %s" % result1
    input_file = "Chain.large.1496809484823.input.txt"
    with open (input_file, "r") as fread:
        for line in fread.readlines():
            switch_num, action_num = line.split(" ")
            print switch_num, action_num
            result = compute_result(string.atoi(switch_num), string.atoi(action_num), result1)
            out_result += "Case #%s: %s\n" % (k, result)
            k += 1
    # write result to out file
    with open("%s_output.txt" % input_file, "w") as fwrite:
        fwrite.write(out_result)
结果如下



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值