三色旗问题

来源:互联网 发布:ubuntu 安装分区建议 编辑:程序博客网 时间:2024/05/01 07:39

问题:假设有一根绳子,上面有一些红、白、蓝色的旗子。起初旗子的顺序是任意的,现在要求用最少的次数移动这些旗子,使得它们按照蓝、白、红的顺序排列。注意只能在绳子上操作,并且一次只能调换两个旗子。

盗一张图:

找了些例子,做法是用三个指针abc,a指向开头,c指向末尾。b从开头至末尾移动,如果发现是蓝色,和a指向的非蓝色交换;如果是白色,则不做任何操作;如果是红色,和c指向的非红色交换.

代码如下:

public static void main(String[] args) { System.out.println("请输入三色旗的顺序"); Scanner scanner=new Scanner(System.in); String s=scanner.next(); s=move(s.toUpperCase().toCharArray()); System.out.println("排列好后的顺序:"+s); }// 互相交换 public static void change(char[] flags,int x,int y){ System.out.println("交换前:"+new String(flags)); char temp=flags[x]; flags[x]=flags[y]; flags[y]=temp; System.out.println((x+1)+" 号和 "+(y+1)+" 号交换"); System.out.println("交换后:"+new String(flags)); } public static String move(char[] flags){ int a=0,b=0; int c=flags.length-1; while(b<=c){ switch (flags[b]){ case 'W': b++; break; case 'B': if(flags[a]=='B') {a++;b++;} else{ change(flags, a, b); a++; b++; } break; case 'R': while(b<c && flags[c]=='R') c--; change(flags, b, c); c--; break; } } return new String(flags); }
但是好像这种做法会存在一些无效的移动,例如BWBWWBR的序列,实际上只需要移动一次,但却移动了2次.

然后换了一种做法,麻烦一点,但似乎可以做到避免无效的移动。

代码如下:

import java.util.Scanner;public class ThreeColorFlags {static int moveTime = 0;public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入一个序列:(如:BBBWWRR)");String input = scanner.nextLine();input = input.toUpperCase();char[] flags = input.toCharArray();// 先统计蓝色和白色共有多少int countB = 0, countW = 0;int length = flags.length;for (char c : flags) {switch (c) {case 'B':countB++;break;case 'W':countW++;break;}}moveAvoidInvalid(flags, countB, countW, length);}public static void moveAvoidInvalid(char[] flags, int countB, int countW, int length) {// 第一步先将蓝区移动完成// 先遍历蓝区(B区),找到W,优先去和W区的B交换;找到R,优先去和R区的B交换// 用三个指针分别指向三个区域int pointB = 0;int pointW = countB;// 从W区正向开始找int pointR = length - 1;// R区逆向开始找while (pointB < countB) {switch (flags[pointB]) {case 'B':pointB++;break;case 'W':if (flags[pointW] == 'B') {exchange(flags, pointB, pointW);pointB++;pointW++;} else {pointW++;}break;case 'R':if (flags[pointR] == 'B') {exchange(flags, pointB, pointR);pointB++;pointR--;} else {pointR--;}break;}}// 经过上一步,蓝色应该移动好了// 第二步,完成白色和红色的移动// 让指针重新指向W去开始和R区的末尾pointW = countB;pointR = length - 1;while (pointW < countB + countW) {switch (flags[pointW]) {case 'W':pointW++;break;case 'R':if (flags[pointR] == 'W') {exchange(flags, pointW, pointR);pointW++;pointR--;} else {pointR--;}break;}}}public static void exchange(char[] flags, int x, int y) {moveTime++;System.out.println("第" + moveTime + "次交换前的序列:" + String.valueOf(flags));char temp = flags[x];flags[x] = flags[y];flags[y] = temp;System.out.println("第" + moveTime + "次交换后的序列:" + String.valueOf(flags));}}

有的地方也还不太确定,发来记录一下。


0 0
原创粉丝点击