d400: A-排列組合

Tags: bitmask, permutation


出處:https://zerojudge.tw/ShowProblem?problemid=d400
提交:https://zerojudge.tw/Submissions?problemid=d400&account=allllllan123456


問題:給你一個僅由不超過 10 個小寫字母 (可能會重複) 組成的字串 $s$,代表 $s$ 內的字母需要重新排列,接著有 m 組字母對 $(ch_{i,1}, ch_{i,2})$ 表示在每個合法排列中對於每個字母對,$ch_{i,1}$ 都一定要比 $ch_{i,2}$ 先出現,注意到前面這句話並不代表 $ch_{i,2}$ 的後方不能存在任何 $ch_{i,1}$。請你按照「每個字母第一次出現在 $s$」的字典序依序印出至多前 10 組彼此不重複的排列。舉例來說,babc 的輸出依序為 bbac, bbca, …, cbba。


解法:這題的考點著重於怎麼處理字母優先順序的問題,我的作法是對於每個字母 ch 都用一個整數 before 的 bits 去記錄有哪些字母 ch2 必須出現在 ch 前面,每個 ch2 都佔了 before 的一個 bit,當我檢查當前已經選入字母的 bitmask 已經滿足 before 的每個 1-bit 的時候,我才能繼續選入 ch。至於題目限定的字典序以及字串不重複的機制可以參考其他 permutation 相關的題目例如 d436d781


延伸:這題的字典序蠻特別的,我原先以為要完全按照輸入字元的順序印出,舉例來說,babc 的輸出依序應為 babc, bacb, bbac, … 等,後來發現這樣子有重複字元的話會非常難實作,就想說猜猜看只根據「每個字母第一次出現在 $s$」的這個順序輸出,沒想到竟然就不小心 AC 辣!!!!!各位不妨想想看要怎麼完全按照輸入字元的順序印出,可是又不能有重複的字串,板主目前是還想不太到啦,這看起來就頗有挑戰性的 ^_^


 1#include <bits/stdc++.h>
 2using namespace std;
 3
 4int len, kind, cnt;
 5char arr[11], ans[11];
 6unsigned before[26], num[26];
 7
 8void dfs(int nowLen, unsigned appeared) {
 9    if (nowLen == len) {
10        if (cnt < 10) cnt++, puts(ans);
11        return;
12    }
13    for (int i=0; i<kind && cnt<10; i++)
14        if (num[arr[i]-'a'] && // 如果必須在 arr[i] 前面出現的字元都已經出現的話
15            ((before[arr[i]-'a']&appeared) == before[arr[i]-'a'])) // 我才能選 arr[i]
16            num[arr[i]-'a']--,
17            ans[nowLen] = arr[i],
18            dfs(nowLen+1, appeared | (1<<(arr[i]-'a'))),
19            num[arr[i]-'a']++;
20}
21
22int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); // IO 優化
23    int m, T; cin >> T;
24    while (T--) { kind = cnt = 0;
25        cin >> arr; len = strlen(arr); memset(num, 0, sizeof num);
26        for (int i=0; i<len; i++)
27            if (!num[arr[i]-'a'])
28                num[arr[i]-'a'] = 1, arr[kind++] = arr[i];
29            else num[arr[i]-'a']++;
30        cin >> m; memset(before, 0, sizeof before);
31        while (m--) {
32            char a, b; cin >> a >> b;
33            before[b-'a'] |= 1 << (a-'a');
34        }
35        dfs(0, 0);
36        if (!cnt) puts("NANJ你唬我");
37    }
38    return 0;
39}

no image