荷蘭國旗問題

/**
 * 荷蘭國旗問題
 * 解題的基本策略:變了兩個顏色區域,如果顏色條不屬於所在的區域,則交換一個屬於該
 * 區域的顏色條。每一次都是必要的交換,從而實現最小交換次數。
*/

#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數據結構原理與經典問題求解》
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章