POJ 3617 Best Cow Line (字典序最小問題 & 貪心)

原題鏈接:http://poj.org/problem?id=3617

問題梗概:給定長度爲 N 的字符串 S, 要構造一個長度爲 N 的字符串 T。起初,T 是一個空串,隨後反覆進行下列任意操作。

  • S 的頭部刪除一個字符,加到 T 的尾部。
  • S 的尾部刪除一個字符,加到 T的尾部。

    目的是要構造字典序儘可能小的字符串 T

    限制條件:

  • 1 \leqslant N \leqslant 2000
  • 字符串 S 只包含大寫英文字母
  • 輸出的字符串每 80 個字符進行一次換行

字典序是指從前到後比較兩個字符串大小的方法。首先比較第 1 個字符,如果不同則第 1 個字符較小的字符串更小,如果相同則繼續比較第 2 個字符......如此繼續,來比較整個字符串的大小。

問題分析:從字典序的性質上看,無論 T 的末尾有多大,只要前面部分的較小就可以。所以我們可以試一下如下貪心算法:

  • 不斷取 S 的開頭和末尾中較小的一個字符放到 T 的末尾。

這個算法已經接近正確了,只是針對 S 的開頭和末尾字符相同的情形還沒有定義。在這種情形下,因爲我們希望能夠儘早使用更小的字符,所以就要比較下一個字符的大小。下一個字符也有可能相同,因此就有如下算法:

  • 按照字典序比較 S 和將 S 反轉後的字符串 S^{'}
  • 如果 S 較小,就從 S 的開頭取出一個文字,追加到 T 的末尾;
  • 如果 S^{'} 較小,就從 S 的末尾取出一個文字,追加到 T 的末尾;
  • 如果相同則取哪個都可以。

根據前面提到的性質,字典序比較類的問題經常能用得上貪心法。


代碼如下:

#include <iostream>
#include <algorithm>
using namespace std;

const int MAX = 2000;
// 輸入
int N;
char S[MAX + 1];

void solve() {
	// 剩餘的字符串爲 S[a], S[a+1],...., S[b]
	int a = 0, b = N - 1, flag = 0;
	
	while (a <= b) {
	
		// 將從左起和從右起的字符串比較
		bool left = false;
		for (int i = 0; a + i <= b; i++) {
			if (S[a + i] < S[b - i]) {
				left = true;
				break;
			}
			else if (S[a + i] > S[b - i]) {
				left = false;
				break;
			}
		} 
		
		if (left) cout << (S[a++]), flag++;
		else cout << (S[b--]), flag++;
		if (flag == 80) cout << endl, flag = 0;
	} 
	cout << endl;
} 

int main() {
	while (cin >> N) {
		for (int i = 0; i < N; i++)
			cin >> S[i];
			
		solve();
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章