三色旗帜分类
问题描述:
假设有一条绳子,上面有红、白、蓝三种颜色的旗子,起初绳子上的旗子颜色并没有顺序,您
希望将之分类,并排列为蓝、白、红的顺序,要如何移动次数才会最少,注意您只能在绳子上
进行这个动作,而且一次只能调换两个旗子。
#include <iostream> #include <time.h> using namespace std; //三色旗算法: //假设有一条绳子,上面有红、白、蓝三种颜色的旗子,起初绳子上的旗子颜色并没有顺序,您 //希望将之分类,并排列为蓝、白、红的顺序,要如何移动次数才会最少,注意您只能在绳子上 //进行这个动作,而且一次只能调换两个旗子。 //算法说明:要使用最少的个数,就是用一个脚标从头开始移动,碰到红色就放到前面,碰到蓝色就放到后面,白色的就不动 //得要三个脚标,一个用来保存红色最后项的位置,一个保存蓝色的 #define maxsize 30 //0表示红色R,1表示白色W,2表示蓝色B #define RED 0 #define WHITE 1 #define BLUE 2 int R = 0;//j记录红色旗帜的位置,初始话0 int scan = 0;//游标,用于全局扫描 int B = maxsize-1;//蓝色旗帜位置,初始化为最大位置的后一位 //输出数组的信息,便于观察 void printf_flag(int *line,int size) { for (int i = 0;i <= size-1;i++) { cout<<line[i]<<" "; } cout<<endl; } int correct_flag(int *line,int begin,int end) { int step = 0;//需要步数 //游标赋值 R = begin; B = end; //游标优化 while(line[B] == BLUE) { B--; } while(line[R] == RED) { R++; } scan = R; //开始扫描 while(scan <= B)//扫描终止条件,游标与末尾的蓝色游标相遇 { while(line[B] == BLUE && B >= scan) { B--; } while(line[R] == RED && R <= scan) { R++; } int temp = line[scan]; switch(line[scan]) { case RED://红色,放入红色区 line[scan] = line[R]; line[R] = temp; step++; R++; if (line[scan] == BLUE) { break; } scan++; break; case WHITE://假如是白色 scan++; break; case BLUE://假如是蓝色 line[scan] = line[B]; line[B] = temp; step++; B--; if (line[scan] == RED) { break; } scan++; break; default: break; } printf_flag(line,maxsize); } return step; } int main() { //定义一个数组,描述绳子上的旗帜 int line[maxsize]; srand((int)time(0)); for (int i = 0;i < maxsize;i++) { line[i] = rand()%3; } printf_flag(line,maxsize); int a = correct_flag(line,0,maxsize-1); cout<<"Total Steps:"<<a<<endl; system("pause"); return 0; }
程序执行结果
代码看起来很长,但是有一部分主要用于代码优化,减少移动次数,比如每次循环开始时进行游标优化等,具体的实现在代码里面都有注释,就不多讲了,(PS,这个程序的容错性还比较差啊)