标题:填字母游戏
小明经常玩 LOL 游戏上瘾,一次他想挑战K大师,不料K大师说:
“我们先来玩个空格填字母的游戏,要是你不能赢我,就再别玩LOL了”。K大师在纸上画了一行n个格子,要小明和他交替往其中填入字母。
并且:
1. 轮到某人填的时候,只能在某个空格中填入L或O
2. 谁先让字母组成了“LOL”的字样,谁获胜。
3. 如果所有格子都填满了,仍无法组成LOL,则平局。小明试验了几次都输了,他很惭愧,希望你能用计算机帮他解开这个谜。
本题的输入格式为:
第一行,数字n(n<10),表示下面有n个初始局面。
接下来,n行,每行一个串,表示开始的局面。
比如:“******”, 表示有6个空格。
“L****”, 表示左边是一个字母L,它的右边是4个空格。要求输出n个数字,表示对每个局面,如果小明先填,当K大师总是用最强着法的时候,小明的最好结果。
1 表示能赢
-1 表示必输
0 表示可以逼平
例如,
输入:
4
***
L**L
L**L***L
L*****L则程序应该输出:
0
-1
1
1资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
这个下棋类的题,之前没碰见过,因此不会做,容易想的复杂。大师用最强着法,百度一搜才知道,“着法”:指下棋路数,或者武术动作。这句话看起来很牛掰。
我一开始理解的是,轮到小明下棋用全排列。轮到大师就用一些能想到的小套路去对应下棋,比如棋盘存在L***L,轮到大师下棋,中间是不会下L,也不会在两边下O。如果没有合适的小套路,在用全排列。可是这不太可能,因为这各种各样的棋盘状态显然不可能短时间实现。最后做出来之后发现其实一点用没有,就是用来误导人的。
后来没思路,在百度找到一个大佬的C++代码,测试通过,然后进行学习,发现思路:
(1)这道题还是普普通通的全排列。(多气人)
(2)大师和小明用的一模一样的下棋方式。
测试网址:https://www.dotcpp.com/oj/problem1845.html
贴上代码:注释应该很详细,不懂就问
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Main {
String s = "";//存字符串
Map<String, Integer> map = new HashMap<String, Integer>();//判重,去除棋盘重复的结果
public Main() {
Scanner sn = new Scanner(System.in);
int q = sn.nextInt();
sn.nextLine();
for (int i = 0; i < q; i++) {
s = sn.nextLine().trim();
System.out.println(check());
map.clear();
}
}
public int check() {
// 检验是否含有可以使一方胜利的棋局
if (s.indexOf("LO*") != -1)
return 1;
if (s.indexOf("L*L") != -1)
return 1;
if (s.indexOf("*OL") != -1)
return 1;
// 无子平局
if (s.indexOf('*') == -1)
return 0;
// 当前棋盘的状态已经存在,只要知道当前状态有结果,不需要管理谁赢谁输,只要返回结果
if (map.get(s) != null)
return map.get(s);
int t = -1;// 记录结果
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '*')// 可以下棋
{
//这里我为什么转成字符数组,当然可以直接用字符串拼接
//但似乎需要if语句判断吧,我拼接有时候报错,因此换成数组就不会了
char[] c = s.toCharArray();
c[i] = 'L';// 下L
s = String.valueOf(c);
/*
* 这里的a1要加符号 我们只单单看第一层,不看递归里面,看深了不好理解
* 我们的每一次check()只是判断当前状态有没有赢的路径,没有规定谁在下棋
* 我们来看第一次调用check(),也就是第一层
* t表示小明赢得可能,初始值为-1,必输 第一层内调用的check()
* 表示进入到大师下棋后的输赢状态
* 那么-check()就会表示小明的结果,因为大师赢,小明就输
* 或者大师输小明就赢,或者平局为0,负号无影响
* 因此t=max(t,-check)为小明能否赢的最好情况。
* 然后返回t输出。 理解了上面说的之后,进入递归,就容易理解了,大师下棋和上述类似
*/
t = max(t, -check());
if (t == 1)
return 1; // 如果当前状态已经赢了,直接返回1,不需要往下进行了
c[i] = 'O';// 下O
s = String.valueOf(c);
t = max(t, -check());
c[i] = '*';
s = String.valueOf(c);// 还原
if (t == 1)
return 1; // 如果当前状态已经赢了,直接返回1,不需要往下进行了
}
}
map.put(s, t);// 存放当前棋局,以及对应的输赢状态,用于判重
return t;
}
public int max(int a, int b) {
return a > b ? a : b;
}
public static void main(String[] args) {
new Main();
}
}
测试100分通过。