找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3409|回复: 0

三色旗问题

[复制链接]
发表于 2015-1-15 18:29:55 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
本帖最后由 0x55AA 于 2015-1-15 18:30 编辑

1 问题由来
    三色旗的问题最早由E.W.Dijkstra所提出,他所使用的用语为Dutch Nation Flag(Dijkstra为荷兰人),而多数的作者则使用Three-Color Flag来称之。
    假设有一条绳子,上面有红、白、蓝三种颜色的旗子,起初绳子上的旗子颜色并没有顺序,您希望将之分类,并排列为蓝、白、红的顺序,要如何移动次数才会最少,注意您只能在绳子上进行这个动作,而且一次只能调换两个旗子。

2 解决思路:
    三种颜色的旗子,白色居中,蓝色开头,红色结尾,如果想要移动的次数最少,那么需要做的就是红色的往后面移动,蓝色的往前面移动,中间的白色尽量不动。
    算法的流程就是用三个信标b,w,r分别指向不同的旗子。其中b指向的从0开始连续排列的Blue旗子的最后面的第一个非Blue旗子,r指向的从最后一个序号开始连续排列的Red旗子的第一非Red旗子。例如:bbrwbbrr,那么b指向的就是序号为2的r,r指向的就是序号为倒数第三的b。w在这里里面起到的作用就是一个可以移动的指针。
    当w指向的旗子是White旗子的时候,w继续向前移动;当w指向的旗子是Blue的时候,就需要把b所指的旗子和w所指的Blue旗子交互;同理当w指的旗子是Red的时候就需要w所指的Red旗子和r所指的旗子交换。
    下图是起始时三个信标所指向的位置。
1.png
3 程序实现
  1. #include <string>
  2. #include <iostream>
  3. using namespace std;

  4. int dutchFlag(string& str);
  5. void swap(string& str,int x,int y);

  6. void main()
  7. {
  8.         cout<<"Please input the dutch flags"<<endl;
  9.         string str;
  10.         cin>>str;
  11.         int nTimes = dutchFlag(str);
  12.         cout<<str<<endl;

  13. }
  14. int dutchFlag(string& str)
  15. {
  16.         int nLength = str.length();
  17.         int fBlue = 0;
  18.         int fWhite = 0;
  19.         int fRed = nLength-1;
  20.         int nCnt = 0;
  21.         while( fWhite <= fRed )
  22.         {
  23.                 if(str[fWhite] == 'w')
  24.                         fWhite++;
  25.                 else if(str[fWhite] == 'b')
  26.                 {
  27.                         if( fWhite != fBlue )
  28.                                 swap(str,fWhite,fBlue);
  29.                         fWhite++;
  30.                         fBlue++;
  31.                         nCnt++;

  32.                 }
  33.                 else
  34.                 {
  35.                         // use fWhite < fRed to avoid 'wr':w point to r,and r point to r,then swap and error
  36.                         while(str[fRed] == 'r' && fWhite < fRed)
  37.                                 fRed--;
  38.                         if( fWhite != fRed )
  39.                                 swap(str,fWhite,fRed);
  40.                         fRed--;
  41.                         nCnt++;
  42.                 }
  43.         }
  44.         return nCnt;
  45. }

  46. void swap(string &str,int x,int y)
  47. {
  48.         char tmp;
  49.         tmp = str[x];
  50.         str[x] = str[y];
  51.         str[y] = tmp;
  52.         cout<<x<<" swaps with "<<y<<endl;
  53. }
复制代码
4 细节问题
4.1 当w和b所指向的位置一样的时候,如果不加限定条件 fWhite != fBlue的话,那么就会造自身的交换;同理当w和r同时指向最后的位置的时候,如果不加限定条件判断两者是否相等,那么也会造成自身与自身交换。
4.2
  1. while(str[fRed] == 'r' && fWhite < fRed)
复制代码
   这个主要是为了防止例如wr的情况,这种情况下w指向r,r开始也指向r,w和r所指向的位置相同,然后r--,再然后w和r交换变成了rw,就这样导致了错误的发生。
加上限制条件 fWhite < fRed,那么此时r就不会再向前移动,因此就不会发生交换,从而避免了错误的发生。

回复

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-22 15:04 , Processed in 0.036367 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表