挑战程序竞赛系列(57):4.6数列上的分治法
2017-09-11 20:19
549 查看
挑战程序竞赛系列(57):4.6数列上的分治法
传送门:POJ 1854: Evil Straw Warts Live翻译参考自:http://www.hankcs.com/program/algorithm/poj-1854-evil-straw-warts-live.html
文字游戏:求通过交换相邻字符使某字符串成为回文的最小步数。
一个回文字符串被定义为等同于自己本身的反转。
给定一个字串,其不一定是个回文,计算最少的swap(交换次数)使这个字串成为回文。
swap操作定义为交换两个相邻字符。
例如字串”mamad” 可以使用三次swaps 转换成回文字串”madam”:
swap “ad” 后的结果为”mamda”
swap “md” 后的结果为”madma”
swap “ma” 后的结果为”madam”
输入第一行有一个整数n表示接下来的数据组数。
对于每组字串,长度最多为100 的小写字母够成,输出最少的交换次数,
如果没办法转换成回文字串,则输出 “Impossible”。
思路:
此题需要明确,不管交换谁,把某个字符移动到某个位置后,在连续交换过程中,其他字符的相对位置不会发生任何变化,所以每个操作可以看作是独立的。那么何来最小的操作步数?
此时可以考虑两端的字符,若两端字符相等不发生任何交换,左+1,右-1,如若不等,选择交换次数最小的那个字符移动,这样问题就回到子问题上。
可以参考hankcs示意图:
操作完毕后,i+1,j-1,继续如下操作:
代码如下:
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.Arrays; import java.util.StringTokenizer; public class Main{ String INPUT = "./data/judge/201709/P1854.txt"; public static void main(String[] args) throws IOException { new Main().run(); } void solve() { int T = ni(); while (T --> 0) { String s = ns(); char[] cs = s.toCharArray(); int n = cs.length; int[] map = new int[32]; for (int i = 0; i < n; ++i) { map[cs[i] - 'a']++; } int cnt = 0; for (int i = 0; i < 32; ++i) { if ((map[i] & 1) != 0) { cnt++; } } if (cnt > 1) out.println("Impossible"); else { out.println(divide(cs, 0, n - 1)); } } } public int divide(char[] cs, int i, int j) { if (i >= j) return 0; char a = cs[i]; char b = cs[j]; if (a == b) { return divide(cs, i + 1, j - 1); } int k = i + 1; while (k < j && cs[k] != b) k++; int op1 = k - i; k = j - 1; while (k > i && cs[k] != a) k--; int op2 = j - k; if (op1 < op2) { int tt = op1 + i; while (tt != i) { swap(cs, tt, tt - 1); tt--; } return op1 + divide(cs, i + 1, j - 1); } else { int tt = j - op2; while (tt != j) { swap(cs, tt, tt + 1); tt++; } return op2 + divide(cs, i + 1, j - 1); } } public void swap(char[] cs, int i, int j) { char tmp = cs[i]; cs[i] = cs[j]; cs[j] = tmp; } FastScanner in; PrintWriter out; void run() throws IOException { boolean oj; try { oj = ! System.getProperty("user.dir").equals("F:\\java_workspace\\leetcode"); } catch (Exception e) { oj = System.getProperty("ONLINE_JUDGE") != null; } InputStream is = oj ? System.in : new FileInputStream(new File(INPUT)); in = new FastScanner(is); out = new PrintWriter(System.out); long s = System.currentTimeMillis(); solve(); out.flush(); if (!oj){ System.out.println("[" + (System.currentTimeMillis() - s) + "ms]"); } } public boolean more(){ return in.hasNext(); } public int ni(){ return in.nextInt(); } public long nl(){ return in.nextLong(); } public double nd(){ return in.nextDouble(); } public String ns(){ return in.nextString(); } public char nc(){ return in.nextChar(); } class FastScanner { BufferedReader br; StringTokenizer st; boolean hasNext; public FastScanner(InputStream is) throws IOException { br = new BufferedReader(new InputStreamReader(is)); hasNext = true; } public String nextToken() { while (st == null || !st.hasMoreTokens()) { try { st = new StringTokenizer(br.readLine()); } catch (Exception e) { hasNext = false; return "##"; } } return st.nextToken(); } String next = null; public boolean hasNext(){ next = nextToken(); return hasNext; } public int nextInt() { if (next == null){ hasNext(); } String more = next; next = null; return Integer.parseInt(more); } public long nextLong() { if (next == null){ hasNext(); } String more = next; next = null; return Long.parseLong(more); } public double nextDouble() { if (next == null){ hasNext(); } String more = next; next = null; return Double.parseDouble(more); } public String nextString(){ if (next == null){ hasNext(); } String more = next; next = null; return more; } public char nextChar(){ if (next == null){ hasNext(); } String more = next; next = null; return more.charAt(0); } } static class ArrayUtils { public static void fill(int[][] f, int value) { for (int i = 0; i < f.length; ++i) { Arrays.fill(f[i], value); } } public static void fill(int[][][] f, int value) { for (int i = 0; i < f.length; ++i) { fill(f[i], value); } } public static void fill(int[][][][] f, int value) { for (int i = 0; i < f.length; ++i) { fill(f[i], value); } } } }
相关文章推荐
- 挑战程序竞赛系列(61):4.6平面上的分治法(1)
- 挑战程序竞赛系列(59):4.6树上的分治法(2)
- 挑战程序竞赛系列(62):4.6平面上的分治法(2)
- 挑战程序竞赛系列(60):4.6树上的分治法(3)
- 挑战程序竞赛系列(58):4.6树上的分治法(1)
- 挑战程序竞赛系列(94):3.6凸包(5)
- 挑战程序竞赛系列(21):3.2反转
- 挑战程序竞赛系列(87):3.6平面扫描(1)
- 挑战程序竞赛系列(31):4.5剪枝
- 挑战程序竞赛系列(8):2.1一往直前!贪心法(其他)
- 挑战程序竞赛系列(52):4.2 Nim 与 Grundy 数
- 挑战程序竞赛系列(16):3.1最大化最小值
- 挑战程序竞赛系列(17):3.1最大化平均值
- 挑战程序竞赛系列(69):4.7后缀数组(1)
- 挑战程序竞赛系列(73):4.7高度数组(3)
- 挑战程序竞赛系列(90):3.6凸包(1)
- 挑战程序竞赛系列(29):3.4熟练掌握动态规划
- 挑战程序竞赛系列(39):4.1模运算的世界(2)
- 挑战程序竞赛系列(40):4.1模运算的世界(3)
- 挑战程序竞赛系列(2):2.3优化递推关系式