清华大学 玛雅人的密码(java)

与世无争的帅哥 提交于 2020-02-03 03:19:16
题目描述
玛雅人有一种密码,如果字符串中出现连续的2012四个数字就能解开密码。给一个长度为N的字符串,(2=<N<=13)该字符串中只含有0,1,2三种数字,问这个字符串要移位几次才能解开密码,每次只能移动相邻的两个数字。例如02120经过一次移位,可以得到20120,01220,02210,02102,其中20120符合要求,因此输出为1.如果无论移位多少次都解不开密码,输出-1。
输入描述:
输入包含多组测试数据,每组测试数据由两行组成。
第一行为一个整数N,代表字符串的长度(2<=N<=13)。
第二行为一个仅由0、1、2组成的,长度为N的字符串。
输出描述:
对于每组测试数据,若可以解出密码,输出最少的移位次数;否则输出-1。
示例1
输入
复制
5
02120
输出
复制
1

解法一:回溯法
有误,只能通过百分之90

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
//13
//1122121122200
public class Main
{
    public static void main(String[] args)
    {
        BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
        try {
            String str;
            while((str=br.readLine())!=null) {
            	int len = Integer.parseInt(str);
            	String mode = br.readLine();
            	char[] ch = mode.toCharArray();
            	if(mode.indexOf("2012") != -1) System.out.println("0");
            	else if(!isVaild(mode)) System.out.println("-1"); 
            	else {
            		int[]res = {len*len};
            		backtrack(res, ch, len-1, 0);
            		System.out.println(res[0]);
            	}
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void backtrack(int[] res, char[] ch, int n, int count) {
    	if(new String(ch).indexOf("2012") != -1) {
    		if(count < res[0]) res[0] = count; 
    		return;
    	}
    	 for (int i = n; i > 0; i--) {
    	      // in the current permutation
    	      swap(ch, i, i-1);
    	      count++;
    	      // use next integers to complete the permutations
    	      backtrack(res, ch, i-1, count);
    	      // backtrack
    	      swap(ch, i, i-1);
    	      count--;
    	 }
    }
    public static void swap(char[] ch, int i, int j) {
    	char temp = ch[i];
    	ch[i] = ch[j];
    	ch[j] = temp;
    }
    public static boolean isVaild(String str) {//只有字符串中同时含有0,1,2时才有可能通过位移产生2012
        boolean b0 = false;
        boolean b1 = false;
        boolean b2 = false;
        for(char c : str.toCharArray()) {
            if(c == '0') {
                b0 = true;
            }else if(c == '1') {
                b1 = true;
            }else if(c == '2') {
                b2 = true;
            }else {
                return false;
            }
        }
        return b0&&b1&&b2;
    }
}

解法二:bfs,从别人那看来的,超级牛逼

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;


public class Main
{
	public static Queue<String> q = new LinkedList<>();
	public static Map<String, Integer> map = new HashMap<>();
    public static void main(String[] args)
    {
        BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
        try {
            String str;
            while((str=br.readLine())!=null) {
            	String mode = br.readLine();
            	char[] ch = mode.toCharArray();
            	if(mode.indexOf("2012") != -1) System.out.println("0");
            	else if(!isVaild(mode)) System.out.println("-1"); 
            	else System.out.println(BFS(mode));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static int BFS(String str) {
    	q.add(str);//初始字符串作为起点放入队列
    	map.put(str, 0);//初始字符串经历的交换次数是0
    	while(!q.isEmpty()) {
    		str = q.poll();//取出队首,存入str
    		for(int i = 0; i < str.length()-1; i++) {//尝试进行一次交换
    			char[] ch = str.toCharArray();
    			swap(ch, i, i+1);//新字符串由str交换i位和i+1位得到
    			String newStr = new String(ch);
    			if(!map.containsKey(newStr)){//如果这个字符串没出现过
    				map.put(newStr, map.get(str)+1);//现在出现过了,且交换次数比他爹多1
    				if(newStr.indexOf("2012") != -1) return map.get(newStr);//符合要求,收工
    				else q.add(newStr);//不合要求,那继续bfs,把它加入队列
    			}
    			else continue;//出现过的字符串,不用进行处理
    		}
    	}
    	return -1;//遍历完成,没发现符合要求的字符串,返回-1
    }
    public static void swap(char[] ch, int i, int j) {
    	char temp = ch[i];
    	ch[i] = ch[j];
    	ch[j] = temp;
    }
    public static boolean isVaild(String str) {//只有字符串中同时含有0,1,2时才有可能通过位移产生2012
        boolean b0 = false;
        boolean b1 = false;
        boolean b2 = false;
        for(char c : str.toCharArray()) {
            if(c == '0') {
                b0 = true;
            }else if(c == '1') {
                b1 = true;
            }else if(c == '2') {
                b2 = true;
            }else {
                return false;
            }
        }
        return b0&&b1&&b2;
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!