1. 程式人生 > 其它 >CF45E - Director(構造性演算法 + 字串 + 貪心 / *2000)

CF45E - Director(構造性演算法 + 字串 + 貪心 / *2000)

45E - Director(源地址自⇔CF45E

目錄

tag

⇔構造性演算法、⇔字串、⇔貪心、⇔*2000

題意

給定 \(N\) 個姓和 \(N\) 個名,要求兩兩組合所有的姓和名,使得姓和名開頭字母相同的對數最多,且全部姓名的總字典序儘可能的小。

思路

賽時思路(是錯的)

點選檢視原因

其實這道題的題意非常難懂,在初見的時候以為這是一道打卡水題,所以想的很簡單,以為只需要按照字典序進行一遍排序即可。結果錯誤了兩次之後發現並不是如此(然而不信邪的隊友便又多交了兩發WA......),題目中最關鍵的那一行條件其實在初見的時候沒有讀出來,原文如下:

First of all Vasya wants to maximize the number of the pairs, in which the name and the surname start from one letter.

需要先將所有首字母相同的姓和名配對,然後再思考字典序的問題。

可是,這道題的難點還不止於此,思考以下樣例:

姓:Sa Ss Aa,名:Sc Sd Sz

如果不考慮字典序,只顧首字母匹配的話,顯然,答案為 \(\tt{}Sa\ Sc,\ Ss\ Sd\)\(\tt{}Aa\ Sz\) ,然而,為了讓總字典序最小,最佳的匹配應當為 \(\tt{}Sa\ Sd,\ Ss\ Sz\)

\(\tt{}Aa\ Sc\)

正解(自己做法)

我們按字典序逆序 ( \(\tt{}Z - A\) )考慮本題。

  • 假如 \(\tt{}name\) 的數量多於 \(\tt{}surname\) ,並且待匹配陣列 \(S\) 中有內容,那麼優先將多餘的 \(\tt{}name\)\(S\) 匹配(注意, \(\tt{}name\) 中字典序升序,直接從尾部取即可,而 \(S\) 中字典序降序,需要從頭部取);

  • 假如 \(\tt{}surname\) 的數量多於 \(\tt{}name\) ,並且待匹配陣列 \(N\) 中有內容,那麼優先將多餘的 \(N\)\(\tt{}surname\)

    匹配(注意, \(\tt{}surname\) 中字典序升序,直接從尾部取即可,而 \(N\) 中字典序降序,需要從頭部取);

  • 完成前兩輪操作後,若仍有 \(\tt{}name\)\(\tt{}surname\) 可匹配,依次配對並放入答案陣列 \(Ans\)

  • 假如匹配完成後仍有多餘的未匹配項,則直接放入對應的待匹配陣列 \(N\)\(S\)

最後,排序 \(Ans\) 陣列並輸出即可。

AC程式碼

點選檢視程式碼
//====================
#define int LL
const int N = 1e6 + 7;
vector<string> name[N], surname[N], ans, _N, _S;
//====================
void Solve() {
	int n; cin >> n;
	for (int i = 1; i <= n; ++ i) {
		string s; cin >> s;
		name[s[0] - 'A'].push_back(s);
	}
	for (int i = 1; i <= n; ++ i) {
		string s; cin >> s;
		surname[s[0] - 'A'].push_back(s);
	}
	for (int i = 25; i >= 0; -- i) {
		auto x = name[i], y = surname[i];
		sort(x.begin(), x.end()), sort(y.begin(), y.end());
		while (_N.size() != 0 && x.size() < y.size()) {
			reverse(_N.begin(), _N.end());
			ans.push_back(_N.back() + " " + y.back());
			_N.pop_back(), y.pop_back();
			reverse(_N.begin(), _N.end());
		}
		while (_S.size() != 0 && x.size() > y.size()) {
			reverse(_S.begin(), _S.end());
			ans.push_back(x.back() + " " + _S.back());
			_S.pop_back(), x.pop_back();
			reverse(_S.begin(), _S.end());
		}
		while (x.size() != 0 && y.size() != 0) {
			ans.push_back(x.back() + " " + y.back());
			x.pop_back(), y.pop_back();
		}
		while (x.size() != 0) {
			_N.push_back(x.back());
			x.pop_back();
		}
		while (y.size() != 0) {
			_S.push_back(y.back());
			y.pop_back();
		}
	}
	sort(ans.begin(), ans.end());
	for (int i = 0; i < n - 1; ++ i) cout << ans[i] << ", ";
	cout << ans.back();
}

錯誤次數

(賽時 1 次)理解錯題意。

(賽後 1 次)也是理解錯了題意。


文 / WIDA
2022.03.25 成文
首發於WIDA個人部落格,僅供學習討論