洛谷 P2065 [TJOI2011]卡片 網絡流
阿新 • • 發佈:2018-08-15
最大匹配 != 網絡 front org pty pan 減少 ++
題面
題目傳送門
解法
顯然的二分圖最大匹配
但是,如果連接\(nm\)條邊的話肯定會出事
考慮如何減少邊的數量
將每一個數分解質因數,將所有出現過的質因數放在中間一排
對於每一個\(a_i\)和\(b_i\),和中間一排能整除自己的質因數連邊
這樣就可以把邊數降低到\(O(n)\)級別
然後dinic即可
代碼
#include <bits/stdc++.h> #define N 1010 using namespace std; template <typename node> void chkmax(node &x, node y) {x = max(x, y);} template <typename node> void chkmin(node &x, node y) {x = min(x, y);} template <typename node> void read(node &x) { x = 0; int f = 1; char c = getchar(); while (!isdigit(c)) {if (c == ‘-‘) f = -1; c = getchar();} while (isdigit(c)) x = x * 10 + c - ‘0‘, c = getchar(); x *= f; } struct Edge { int next, num, c; } e[N * N]; int s, t, cnt, a[N], b[N], l[N * 2], cur[N * 2], num[N * 2]; void add(int x, int y, int c) { e[++cnt] = (Edge) {e[x].next, y, c}; e[x].next = cnt; } void Add(int x, int y, int c) { add(x, y, c), add(y, x, 0); } bool bfs(int s) { for (int i = 1; i <= t; i++) l[i] = -1; queue <int> q; q.push(s); while (!q.empty()) { int x = q.front(); q.pop(); for (int p = e[x].next; p; p = e[p].next) { int k = e[p].num, c = e[p].c; if (c && l[k] == -1) l[k] = l[x] + 1, q.push(k); } } return l[t] != -1; } int dfs(int x, int lim) { if (x == t) return lim; int used = 0; for (int p = cur[x]; p; p = e[p].next) { int k = e[p].num, c = e[p].c; if (c && l[k] == l[x] + 1) { int w = dfs(k, min(c, lim - used)); e[p].c -= w, e[p ^ 1].c += w; if (e[p].c) cur[x] = p; used += w; if (used == lim) return lim; } } if (!used) l[x] = -1; return used; } int dinic() { int ret = 0; while (bfs(s)) { for (int i = 0; i <= t; i++) cur[i] = e[i].next; ret += dfs(s, INT_MAX); } return ret; } int main() { int T; read(T); while (T--) { int n, m; read(n), read(m); set <int> st; for (int i = 1; i <= n; i++) { read(a[i]); int x = a[i]; for (int j = 2; j * j <= x; j++) { if (x % j == 0) { st.insert(j); while (x % j == 0) x /= j; } } if (x > 1) st.insert(x); } for (int i = 1; i <= m; i++) { read(b[i]); int x = b[i]; for (int j = 2; j * j <= x; j++) { if (x % j == 0) { st.insert(j); while (x % j == 0) x /= j; } } if (x > 1) st.insert(x); } int len = 0; for (set <int> :: iterator it = st.begin(); it != st.end(); it++) num[++len] = *it; s = 0, t = cnt = n + m + len + 1; if (cnt % 2 == 0) cnt++; for (int i = 0; i <= t; i++) e[i].next = 0; for (int i = 1; i <= n; i++) Add(s, i, 1); for (int i = 1; i <= m; i++) Add(i + n + len, t, 1); for (int i = 1; i <= n; i++) for (int j = 1; j <= len && num[j] <= a[i]; j++) if (a[i] % num[j] == 0) Add(i, j + n, 1); for (int i = 1; i <= m; i++) for (int j = 1; j <= len && num[j] <= b[i]; j++) if (b[i] % num[j] == 0) Add(j + n, i + len + n, 1); cout << dinic() << "\n"; } return 0; }
洛谷 P2065 [TJOI2011]卡片 網絡流