公众号:编程驿站
习题一、象棋(Xiangqi,ACM/ICPC Fuzhou 2011,UVa1589)考虑一个象棋残局,其中红方有n(2≤n≤7)个棋子,黑方只有一个将。红方除了有一个帅(G)之外还有3种可能的棋子:车(R)、马(H)、炮(C),并且需要考虑蹩马腿(如图2.7所示)和将与帅不能照面(将帅如果同在一条直线上,中间又不隔着任何棋子的情况下,走子的一方获胜)的规则。输入所有棋子的位置,保证局面合法并且红方已经将军。你的任务是判断红方是否已经把黑方将死。关于中国象棋的相关规则请参见原题。
【分析】要判断黑方是否必死,其实就是反过来判断黑方是否有种走法,在走出一步之后能不被红方的任何一个棋子将死。首先判断,黑方是不是可以直接将红方将死,如果可以,就无须进行下一步的判断。然后挨个尝试黑方的各种合法走法(水平或者垂直,但是不能走出黑子的大本营)。如果所有走法都会导致被红方某个棋子吃掉,说明红方必胜。需要特别注意的是,黑方走子时是可以吃掉红方棋子的,如果有这种情况,需在吃子之后再判断输赢。从实现过程中来说,有一个公共的过程可以抽取:就是判断一个棋子是否可以从一个点p1直接水平或者垂直地走到另外一个点p2,中间有0个(车要吃子或者黑将直接将军)或者恰好1个棋子(红炮要将军)。实现中,需要将跳马的8个方向封装成向量。
习题2 莫尔斯电码(Morse Mismatches, ACM/ICPC World Finals 1997,UVa508)输入每个字母的Morse编码、一个词典以及若干个编码。对于每个编码,判断它可能是哪个单词。如果有多个单词精确匹配,任选一个输出并且后面加上“!”;如果无法精确匹配,可以在编码尾部增加或删除一些字符以后匹配某个单词(增加或删除的字符应尽量少)。如果有多个单词可以这样匹配上,任选一个输出并且在后面加上“?”。
【分析】输入时,首先建立字符到对应Morse编码的映射map。每输入一个单词,通过这个map将每一个字符翻译成Morse编码,然后建立所有Morse编码到对应单词的映射map<string ,vector > context。然后对于每一个输入的Morse编码M,首先在context中查找M对应的所有可能的单词v。如果v中只有一个单词,则输出这个单词即可;如果v中包含多个单词,则任意输出一个再加“!”。如果不存在对应的v,则查找context中所有符合以下条件的Morse编码CM:CM为M的前缀或者M为CM的前缀。找到其中长度和M相差最小的那个CM输出即可。找到的所有CM可以用map<int,string>存放,key为CM和M的大小的差,value就是CM本身。因为map本身就是根据key来排序的,直接输出第一个元素即可。