我正在通过解决以前的GCJ问题来学习Python。这个问题很容易解决,但我希望对我的代码进行预先检查(更多Pythonic表达式和更高效的算法)。
魔术师首先在方格中排列16张牌:4行牌,每行4张牌。每张卡都有一个从1到16不同的数字,写在显示的一侧。接下来,魔术师请一位志愿者选择一张牌,并告诉他那张牌在哪一行。最后,魔术师再次将16张牌排列在方格格中,可能是以不同的顺序排列。再一次,他问志愿者她的卡在哪一行。只有这两个问题的答案,魔术师才能正确地决定志愿者选择哪一张牌。太棒了,对吧?你决定写一个程序来帮助你理解魔术师的技巧。该程序将给出卡片的两种安排,以及志愿者对这两个问题的回答:第一次安排中所选卡片的行号和第二次排列中所选卡片的行号。从上到下,行号从1到4。您的程序应该确定志愿者选择了哪一张卡;或者如果志愿者可能选择了多张卡(魔术师做得很糟糕);或者如果没有符合志愿者答案的卡片(志愿者作弊)。输入输入的第一行给出测试用例的数量,T测试用例紧随其后。每个测试用例都从包含一个整数的一行开始:第一个问题的答案。接下来的4行表示卡片的第一次排列:每一行包含4个整数,由一个空格分隔。下一行包含第二个问题的答案,下面四行包含相同格式的第二个排列。输出每个测试用例,输出一行包含“case #x: y”的行,其中x是测试用例编号(从1开始)。如果志愿者可以选择一张卡,那么y应该是卡上的号码。如果志愿者可以选择多张牌,Y应该是“坏魔术师!”,没有引号。如果没有符合志愿者答案的卡片,Y应该被“志愿者欺骗!”,没有引号。文本必须是完全正确的,所以考虑从这里复制/粘贴它。样本输入3 2 1 2 3 4 5 6 7 8 9 10 11 12 14 14 15 3 2 2 2 4 3 3 11 11 9 10 7 12 13 14 4 6 9 2 2 3 4 5 6 7 9 10 11 12 14 15 16 2 2 3 4 5 6 7 8 9 10 12 13 14 15 16 2 2 2 3 4 5 6 8 9 10 11 14 15 16 12 14 14 2 4 4 4 5 5 6 8 9 10 12 14 15 16 1 12 14 14 1 4 4 3 4 5 5 9 10 12 14 14 15 16输出案例1:7例2:坏魔术师!案例3:志愿者受骗!
这是我的密码:
import sys
from itertools import repeat
def main():
submit = False
filename = "A-small-practice"
sys.stdin = open(filename + ".in")
if submit:
sys.stdout = open(filename + ".out", "w")
test_cases = int(input())
main2(test_cases)
def main2(test_cases):
for cn in range(1, test_cases + 1):
print "Case #" + str(cn) + ":",
choices = {}
# Each test case has 2 answers.
for i in repeat(None, 2):
# Volunteer's answer (row # which contains his choice)
row = int(input())
# Cards are in 4 rows.
for r in range(1, 5):
nums = raw_input()
if r == row:
# A row has 4 cards.
for n in nums.split():
choices[n] = choices.get(n, 0) + 1
# The chosen card(s) would be appeared twice.
# So, pick items in choices whose value(appearance) is 2, and filter
# others.
choices = {k: v for k, v in choices.iteritems() if v == 2}
# Only one choice should exist after filtering.
if len(choices) == 1:
print choices.keys()[0]
elif len(choices) > 1:
print "Bad magician!"
else:
print "Volunteer cheated!"
main()欢迎任何意见。
发布于 2017-02-03 08:53:04
main是保留的,所以没关系,但是main2没有任何意义。这个名称应该是函数的一个提示,我会选择guess_card。input和raw_input,为什么?如果您想要进行输入验证,您应该正确地执行它,尝试解析它并最终捕获异常。但是,如果你沿着这条路走下去,那么你也不应该假设其余的输入是正确的。我想说的是,对于这个特定的程序,您可以安全地说,输入的语法会很好。以下是我的看法:
def guess_card(user_rows, card_rows):
possible_answers = []
possible_cards = card_rows[user_rows[0] - 1]
for card in possible_cards:
if card in card_rows[user_rows[1] + 3]:
possible_answers.append(card)
if len(possible_answers) > 1:
return 'Bad magician!'
if len(possible_answers) == 0:
return 'Volunteer cheated!'
return possible_answers[0]
def main():
n_test_cases = int(raw_input())
answers = []
while n_test_cases:
n_test_cases -= 1
user_rows = []
card_rows = []
user_rows.append(int(raw_input()))
for i in range(0, 4):
card_rows.append(raw_input().split(' '))
user_rows.append(int(raw_input()))
for i in range(4, 8):
card_rows.append(raw_input().split(' '))
answers.append(guess_card(user_rows, card_rows))
for answer in answers:
print answer
if __name__ == "__main__":
main()如果您想了解if __name__ == "__main__":行,可以查看这里。
发布于 2017-02-03 13:53:59
with 一般情况下任何与外界联系的事物。with语句会自动处理块末尾这些烦人的对象的清理。
)
大多数内置Python函数都适用于这些对象。使用它们可以让您使用更多方便的Python内置程序。
关于这一点:
如:
file_lines = [i[:-1] for i in open("input.txt")]您还可以将它与with函数一起使用。立即将文件处理程序对象转换为列表意味着您可以尽快开始使用这些惊人的Python功能。
set对象查找匹配魔术师的戏法是通过在移动卡片之前和之后找到两行共有的卡片。让我们称它们为a和b。一旦将两行作为集合,就很容易找到常见的卡片:
a.intersection(b)split处理字符串输入数据。做这件事干得好。在for n in nums.split中。事实上,大多数分配都是简单的字符串操作,这实际上不需要在代码中进行大量修饰。
我在下面添加了我对这项任务的简短、简单的处理:
message = ["Bad magician!",0] + ["Volunteer cheated!"]*3
file_lines = [i[:-1] for i in open("input.txt")]
for i in range(int(file_lines[0])):
offset = (i * 10) + 1
a = set(file_lines[offset + 0 + int(file_lines[offset + 0])].split(" "))
b = set(file_lines[offset + 5 + int(file_lines[offset + 5])].split(" "))
message[1] = a.intersection(b)
print("Case #" + str(i + 1) + ": " + str(message[len(message[1])]))(注:它很可能是一个面向对象的版本将是最可重用的,并适用于其他项目。如果你想知道这方面的想法,问我或这里的其他人。)
https://codereview.stackexchange.com/questions/154334
复制相似问题