BZOJ 4514: [Sdoi2016]数字配对
要求的即为,在费用不小于0的情况下的最大匹配数。
可转化为费用不大于0(负费用)的最大匹配。
在每次spfa得到的cost的时候就判断一下加上是否大于0了,如果大于0就可以直接加上答案并返回了。
#include <bits/stdc++.h> #define ll long long using namespace std; inline int read() { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); } return x * f; } const int N = 3e4 + 10; const ll INF = 0x3f3f3f3f3f3f3f3f; const int inf = 0x3f3f3f3f; struct E { int v, ne, f; ll c; } e[N]; int head[210], cnt, path[210], n, a[210], b[210]; ll dis[210], c[210]; int pm[32005], pn, si[210], sn, di[210], dn, ans; bool vis[32005]; inline void add(int u, int v, int f, ll c) { e[cnt].v = v; e[cnt].f = f; e[cnt].c = -c; e[cnt].ne = head[u]; head[u] = cnt++; e[cnt].v = u; e[cnt].f = 0; e[cnt].c = c; e[cnt].ne = head[v]; head[v] = cnt++; } bool spfa(int s, int t) { memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); memset(path, -1, sizeof(path)); queue<int> que; dis[s] = 0; while (!que.empty()) que.pop(); que.push(s); vis[s] = true; while (!que.empty()) { int u = que.front(); que.pop(); vis[u] = false; for (int i = head[u]; ~i; i = e[i].ne) { int v = e[i].v, f = e[i].f; ll c = e[i].c; if (f && dis[v] > dis[u] + c) { dis[v] = dis[u] + c; path[v] = i; if (!vis[v]) { vis[v] = true; que.push(v); } } } } return dis[t] != INF; } void mcf(int s, int t) { ll cost = 0; while (spfa(s, t)) { int x = inf; for (int i = path[t]; ~i; i = path[e[i^1].v]) x = min(x, e[i].f); if (cost + dis[t] * x <= 0) { cost += dis[t] * x; ans += x; for(int i = path[t]; ~i; i = path[e[i^1].v]) e[i].f -= x, e[i^1].f += x; } else { ans += (-cost) / dis[t]; return; } } } void gp() { for (int i = 2; i <= 32000; i++) { if (!vis[i]) pm[++pn] = i; for (int j = 1; j <= pn && i * pm[j] <= 32000; j++) { vis[i * pm[j]] = true; if (i % pm[j] == 0) break; } } } inline bool check(int x, int y) { if (!x || !y) return false; if (x < y) swap(x, y); if (x % y != 0) return false; x /= y; for (int i = 1; i <= pn; i++) { if (pm[i] >= x) break; if (x % pm[i] == 0) return false; } return true; } int main() { gp(); memset(head, -1, sizeof(head)); n = read(); for (int i = 1; i <= n; i++) a[i] = read(); for (int i = 1; i <= n; i++) b[i] = read(); for (int i = 1; i <= n; i++) c[i] = read(); for (int i = 1; i <= n; i++) { int temp = a[i], cnn = 0; for (int j = 1; j <= pn; j++) { while (temp % pm[j] == 0) { temp /= pm[j]; cnn++; } if (temp == 1) break; } if (cnn & 1) si[++sn] = i; else di[++dn] = i; } for (int i = 1; i <= sn; i++) { for (int j = 1; j <= dn; j++) { if (check(a[si[i]], a[di[j]])) { add(si[i], di[j], inf, c[si[i]] * c[di[j]]); } } } int s = n + 1, t = n + 2; for (int i = 1; i <= sn; i++) add(s, si[i], b[si[i]], 0); for (int i = 1; i <= dn; i++) add(di[i], t, b[di[i]], 0); mcf(s, t); printf("%d\n", ans); return 0; }