荷兰国旗问题

荷兰国旗问题

    上方的图片便是一个荷兰国旗,从图中我们可以很清楚的看出它的特点,它有三个区域组成,即红,白,蓝。

好,现在我们的问题出来了。现在我们面前有一张桌子,桌子上整齐的摆放着红色,白色,蓝色三种线条,但他们的顺序是凌乱的。

要求是:用一个算法把这些线条挑出来重新摆放顺序,最后的结果就像上图的荷兰国旗,红色在上,白色在中间,蓝色在最下面。

另外,要求在O(n)的复杂度下,使移动次数最少。

算法分析如下:

    荷兰国旗问题其实是一个排序问题。可以将红,白,蓝3种颜色分别用数字0、1和2表示,并使用一个数组来存储它们。将相同颜色

的线条归为一类就相当于将数组中的数组按大小进行排序,只不过数组里存储的数值只有3种而已。其解题的基本策略是遍历两个颜色区域,

如果颜色条不属于所在区域,则交换一个属于该区域的颜色条。这样,每一次都是必要的交换,从而实现最少交换次数。

代码如下:

#include <iostream>
using namespace std;
const int N=10;
int flag[N];  //国旗颜色条数组
int pre[N];   //记录该白条的前白条位置
int split1;   //区域分割1
int split2;   //区域分割2
int blue_red; //红条在蓝色区域的标记
int white_red; //红条在白色区域的标记
int counts = 0;

void out()
{
 for (int i=0;i<N;i++)
 {
  cout<<flag[i];
 }
 cout<<endl;
}

void swap(int& x,int& y)
{
 int temp=x;
 x=y;
 y=temp;

 counts++;
}

void work()
{
 for (int i=0;i<split1;i++)   //红色区域:交换非红条
 {
  if (flag[i]!=0)     //如果不属于该区域
  {
   if(blue_red>=split2)
   {
     swap(flag[i],flag[blue_red]);
     blue_red = pre[blue_red];
   }
   else{
    swap(flag[i],flag[white_red]);
    white_red = pre[white_red];
   }
  }
 }
 int  b=N-1;  //白、蓝区域
 for ( i=split1;i<split2;i++)
 {
  if (flag[i] != 1)
  {
   while (flag[b]==2) b--;
   swap(flag[i],flag[b]);
   b--;
  }
 }
}

//初始化
void init()
{
 int red_num = 0;  //统计红色条数
 int white_num = 0; //统计白色条数
 int preI = -1;
 for (int i=0;i<N;i++)
 {
  flag[i] = rand()%3;
  if (flag[i]==0)
  {
   red_num++;
   pre[i] = preI;
   preI=i;
  }
  else
   if (flag[i]==1)
   {
    white_num++;
   }
 }
   
 //将国旗分成3个颜色区域:
 //0~split-1(红),split1~split2-1(白),split2~N-1(蓝)
 split1=red_num;
 split2=red_num+white_num;
 blue_red=preI;
 i=split2-1;
 while (flag[i] !=0) i--;
 white_red = i;
}

int main()
{
 init();
 cout<<"原始:"<<endl;
 out();

 work();
 cout<<"移动"<<counts<<"次:"<<endl;
 out();

 return 0;

}

 

posted @ 2013-04-11 16:06  小菜美妞成长中  阅读(583)  评论(0编辑  收藏  举报