/**
* 荷兰国旗问题
* 解题的基本策略:变了两个颜色区域,如果颜色条不属于所在的区域,则交换一个属于该
* 区域的颜色条。每一次都是必要的交换,从而实现最小交换次数。
*/
#include <iostream>
using namespace std;
const int N = 100;
int flag[N]; // 国旗颜色条数组
int pre[N]; // 记录该红条的前红条位置
int split1; // 区域分隔1
int split2; // 区域分隔2
int blue_red; // 红条在蓝色区域的标记
int white_red; // 红条在白色区域的标记
int counts = 0;
// print
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(0 != flag[i]) { // 如果不属于该区域
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(int i = split1; i < split2; i++) {
if(1 != flag[i]) {
while(2 == flag[b]) { b--; }
swap(flag[i], flag[b]);
b--;
}
}
}
// initialize
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(0 == flag[i]) {
red_num++;
pre[i] = preI;
preI = i;
} else if(1 == flag[i]) {
white_num++;
}
}
// 将国旗分成三个颜色区域
// 0~split1-1(red), split1~split2-1(white), split2~N-1(blue)
split1 = red_num;
split2 = red_num + white_num;
blue_red = preI;
int i = split2 - 1;
while(0 != flag[i]) { i--; }
white_red = i;
}
int main() {
init();
cout << "原始:" << endl;
out();
work();
cout << "移动" << counts << "次:" << endl;
out();
return 0;
}
转自左飞《CPP数据结构原理与经典问题求解》
荷兰国旗问题
最新推荐文章于 2022-02-16 20:37:00 发布