1. 程式人生 > 其它 >CodeForces - 1487C Minimum Ties(建圖、模擬)

CodeForces - 1487C Minimum Ties(建圖、模擬)

Problem - C - Codeforces

題目大意:

給定一個完全圖,每個隊伍就是一個點,每場比賽就是一條無向邊。現在每次可以消掉一個環,使得剩下的邊最少。

思路:

有這樣一個結論,將一個完全圖分成若干個環逐個消去,所有節點出現在所有環上的總次數都相同。

舉個例子,比如六階完全圖,可以拆成(0-index):

0 1 2 3 4 5 
0 2 4 
1 3 5

三個環,每個節點都總共出現了兩次。

接下來我們可以 \(\mathcal O(n^3)\) 的進行模擬刪環,記錄答案。

列舉起點和步長,再 check 是否能構成環,如能構成則標記。

Code:
int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T; cin >> T;
    while (T--) {
        int n; cin >> n;
        vector<vector<int>> ans(n, vector<int>(n)); //勝負關係,即答案
        vector<vector<int>> ck(n, vector<int>(n)); //邊被佔用為1
        for (int st = 0; st < n; st++) {
            for (int len = 1; len < n; len++) {
                vector<bool> vis(n); //點的訪問情況
                int now = st;
                bool ok = true;
                while (!vis[now]) {
                    vis[now] = true;
                    int nxt = (now + len) % n;
                    if (!ans[now][nxt] && !ans[nxt][now] && !ck[now][nxt] && !ck[nxt][now]) {
                        ck[now][nxt] = ck[nxt][now] = 1;
                        now = nxt;
                    } else {
                        ok = false;
                        break;
                    }
                }
                fill(vis.begin(), vis.end(), false);
                now = st;
                while (!vis[now]) { //線性刪除邊佔用標記,不然會超時
                    vis[now] = true;
                    int nxt = (now + len) % n;
                    ck[now][nxt] = ck[nxt][now] = 0;
                }
                if (!ok) {
                    continue;
                }
                now = st;
                fill(vis.begin(), vis.end(), false);
                while (!vis[now]) {
                    // cerr << now << " ";
                    vis[now] = true;
                    int nxt = (now + len) % n;
                    ans[now][nxt] = 1;
                    ans[nxt][now] = -1;
                    now = nxt;
                }
                // cout << endl;
            }
        }    
        // cout << "####" << endl;    
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                cout << ans[i][j] << " \n"[j == n - 1 && i == n - 2];
            }
        }
    }
    return 0;
}