三色旗---算法集

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

解法
三种颜色的旗子,白色居中,蓝色开头,红色结尾,如果想要移动的次数最少,那么需要做的就是红色的往后面移动,蓝色的往前面移动,中间的白色尽量不动。
算法的流程就是用三个信标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所指的旗子交换。
下图是起始时三个信标所指向的位置。
在这里插入图片描述
补充思考:
只能在一条绳子上移动,表示不能使用其它的辅助数组。问题的要实现三种旗子的分类,这里我们引入三个变量 bFlag, wFlag, rFlag 做标志,如图所示:
在这里插入图片描述

变量意义:

区间 意义
[0,bflag) 已经分好的蓝色旗子
[bflag,wflag) 已经分好的白色旗子
[wflag,rflag) 未分类的旗子
[rflag,len) 已经分好的红色旗子

其中len表示绳子上旗子总个数, 这里的区间表示的是数组下标或旗子编号(0~len-1)区间。
用wFlag位置做判断标准,每次进行如下处理:

  1. 遇到蓝色旗子,交换wFlag和bFlag位置的旗子,并且wFlag和bFlag都向后移动一个位置。
  2. 遇到白色旗子,不处理,wFlag向后移动一个位置。
  3. 遇到红色旗子,交换wFlag和rFlag位置的旗子,rFlag向前移动若干个位置直到为非红色旗子,注意不移动wFlag,因为交换后wFlag位置不一定是白色旗子。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

int main()
{
	char color[100];
	cin>>color;
	int wflag=0,bflag=0,rflag=strlen(color)-1;
	int minstep=0;
	while(wflag<=rflag)
	{
		if(color[wflag]=='b')
		{
			if(bflag!=wflag)
			{
				swap(color[bflag],color[wflag]);
				minstep++;
			};
			bflag++;
			wflag++;
		}	
		else if(color[wflag]=='w')
		    wflag++;
		else
		{
			while(wflag<rflag&&color[rflag]=='r')
			      rflag--;
			if(wflag!=rflag)
			{
				swap(color[wflag],color[rflag]);
				minstep++;
			}
		    rflag--; 
		}
	}
	cout<<color<<endl;
	cout<<"minstep="<<minstep<<endl;
	return 0;
}	
发布了106 篇原创文章 · 获赞 53 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_43595030/article/details/103996073
今日推荐