三色旗问题
来源:互联网 发布:25岁用什么精华知乎 编辑:程序博客网 时间:2024/04/26 06:26
参考:http://caterpillar.onlyfun.net/Gossip/AlgorithmGossip/ThreeColorsFlags.htm
问题:假设有一根绳子,上面有一些红、白、蓝色的旗子。起初旗子的顺序是任意的,现在要求用最少的次数移动这些旗子,使得它们按照蓝、白、红的顺序排列。注意只能在绳子上操作,并且一次只能调换两个旗子。
解法:从绳子的开头(最左边)开始,遇到蓝色的往前移,遇到白色的不动,遇到红色的往后移。
注:我们这里说的前移指往左,后移指往右。
再来看具体的代码实现,先看下图:
我们可以定义三个指针 a、b、c 。从上图可以看出,a和b指向第一个元素,c指向最后一个元素。a的作用是确保蓝色的旗子移到左边,而c的作用是确保红色的旗子移到右边。b则用于顺序访问各个旗子。
思路如下:查看b所指向的旗子的颜色,如果是白色的,则不移动任何旗子(因为要求白色的旗子在中间,所以不去动它),将b往后移一位。
如果是红色的,此时将b所指向的旗子和c所指向的旗子交换位置,同时c往前移一位。(交换后c指向的已经是红色的旗子了,所以可以往前移一位了)。
如果是蓝色的,此时将b所指向的旗子和a所指向的旗子交换位置,同时a往后移一位。(交换后a指向的已经是蓝色的旗子了,所以可以往后移一位了)。这里要注意的是b也要后移一位。(这里我也没有弄得很清楚。大概是b不能在a的后面)
那么什么时候停止交换呢?显然是c都跑到b的后面去的时候,即b>c
根据以上的分析,可以写出如下代码:
import java.util.*;public class ThreeColorFlag {public static void main(String[] args) { System.out.println("请输入三色旗的顺序(例如 BRRWWB):"); Scanner scanner=new Scanner(System.in); String s=scanner.next(); ThreeColorFlag tcf=new ThreeColorFlag(); s=tcf.move(s.toUpperCase().toCharArray()); System.out.println("排列好后的顺序:"+s);}//互相交换public 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 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': change(flags, a, b); a++; b++; break; case 'R': change(flags, b, c); c--; break; } } return new String(flags);}}
运行结果:
请输入三色旗的顺序(例如 BRRWWB):
BBRWBWR
交换前:BBRWBWR
1 号和 1 号交换
交换后:BBRWBWR
交换前:BBRWBWR
2 号和 2 号交换
交换后:BBRWBWR
交换前:BBRWBWR
3 号和 7 号交换
交换后:BBRWBWR
交换前:BBRWBWR
3 号和 6 号交换
交换后:BBWWBRR
交换前:BBWWBRR
3 号和 5 号交换
交换后:BBBWWRR
排列好后的顺序:BBBWWRR
查看以上的结果,我们发现了一些冗余的操作,比如1 号和 1 号交换、2 号和 2 号交换。这显然是多余的,只需要注意一些细节就可以避免它们。
第一,当b指向的是红色而和c交换时,如果此时c指向的是红色,显然没有必要把两个红色的旗子交换。所以这时应该把c前移,直到c指向的不是红色的时候才和b指向的旗子交换。当然移动时必须确保b<c。
第二,同样地,当b指向的是蓝色而要和a的指向交换时,如果a指向的不是蓝色,则交换。否则如果a指向的是蓝色,则也没有必要把两个蓝色的旗子交换。所以这时应该把a和b都往后移一位。
a和b的交换总有一些特殊。大概是因为它们初始都指向第一个元素的缘故吧。如果是从右往左考察每个旗子,也就是说b和c初始指向最后一个元素,那么就该轮到b和c的交换特殊了吧。
改进后的代码:
import java.util.*;public class ThreeColorFlag {public static void main(String[] args) { System.out.println("请输入三色旗的顺序(例如 BRRWWB):"); Scanner scanner=new Scanner(System.in); String s=scanner.next(); ThreeColorFlag tcf=new ThreeColorFlag(); s=tcf.move(s.toUpperCase().toCharArray()); System.out.println("排列好后的顺序:"+s);}//互相交换public 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 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);}}
运行结果:
请输入三色旗的顺序(例如 BRRWWB):
BBRWBWR
交换前:BBRWBWR
3 号和 6 号交换
交换后:BBWWBRR
交换前:BBWWBRR
3 号和 5 号交换
交换后:BBBWWRR
排列好后的顺序:BBBWWRR
这就是我们要的最少的交换步骤了。
~完~
- 三色旗问题
- 三色旗问题
- 三色旗问题
- 三色旗排序问题
- 三色旗排序问题
- 三色旗问题
- 三色旗问题
- 三色旗问题
- 三色旗问题
- 三色旗问题
- 三色旗问题
- 三色旗问题
- 三色旗问题
- 三色旗的问题
- 三色旗问题
- 三色旗问题的解决
- Algorithm Gossip:三色旗问题
- 三色问题
- 在rescue模式修复GRUB
- 一篇很真诚的年终感言
- Could not load file or assembly
- 写程序的一些技巧总结
- XP硬盘安装Ubuntu 10.10系统
- 三色旗问题
- Boa服务器移植
- 高并发服务器实现策略
- 杭电2033 A+B
- Python 正则表达式 RE模块的使用方法
- 关于网络编程五种IO模型的形象比喻
- QCon大会Mike Lee:如何开发靠谱的应用
- 散列(hash)
- struts2文件上传