CodeForces - 1487C Minimum Ties(建圖、模擬)
阿新 • • 發佈:2021-11-30
題目大意:
給定一個完全圖,每個隊伍就是一個點,每場比賽就是一條無向邊。現在每次可以消掉一個環,使得剩下的邊最少。
思路:
有這樣一個結論,將一個完全圖分成若干個環逐個消去,所有節點出現在所有環上的總次數都相同。
舉個例子,比如六階完全圖,可以拆成(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; }