题目描述
思路
很显然,当两个点之间两个条件都不满足,那么这两个点不能共存。但这样连出来的边不一定是二分图,不能直接用最大权闭合子图来解决。
则考虑拆点来构造二分图并互相连边,最后答案除以二即可。
关于最大权闭合子图戳这里 最小割的一些理解和应用
代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000 + 10;
const int MAXNODE = MAXN * 2;
const int MAXEDGE = MAXN * 2 + MAXN * MAXN;
const int INF = 0x3f3f3f3f;
struct Maxflow {
struct {
int v, f, n;
} e[MAXEDGE << 1];
int G[MAXNODE], edgeCnt;
void _add(int u, int v, int f)
{
e[++edgeCnt].n = G[u];
G[u] = edgeCnt;
e[edgeCnt].v = v;
e[edgeCnt].f = f;
}
void add(int u, int v, int f)
{
_add(u, v, f);
_add(v, u, 0);
}
int S, T;
int dep[MAXNODE];
int cur[MAXNODE];
bool bfs()
{
queue<int> que;
memset(dep, -1, sizeof(dep));
que.push(S);
dep[S] = 0;
while (!que.empty()) {
int u = que.front();
que.pop();
cur[u] = G[u];
for (int i = G[u]; i; i = e[i].n)
if (dep[e[i].v] == -1 && e[i].f) {
dep[e[i].v] = dep[u] + 1;
que.push(e[i].v);
}
}
return dep[T] != -1;
}
int dfs(int u, int a)
{
if (u == T || a == 0)
return a;
int flow = 0;
for (int& i = cur[u]; i; i = e[i].n)
if (dep[e[i].v] == dep[u] + 1) {
int f = dfs(e[i].v, min(a, e[i].f));
flow += f;
a -= f;
e[i].f -= f;
e[i^1].f += f;
if (a <= 0)
break;
}
return flow;
}
int dinic()
{
int flow = 0;
while (bfs())
flow += dfs(S, INF);
return flow;
}
void init(int s, int t)
{
S = s, T = t;
edgeCnt = 1;
}
} flow;
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
inline long long sqr(int x) { return 1ll * x * x; }
int main()
{
ios::sync_with_stdio(0);
int n;
static int a[MAXN], b[MAXN];
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%d", a + i);
int ans = 0;
for (int i = 1; i <= n; ++i) {
scanf("%d", b + i);
ans += b[i];
}
int S = 0, T = 2 * n + 1;
flow.init(S, T);
for (int i = 1; i <= n; ++i)
flow.add(S, i, b[i]), flow.add(i + n, T, b[i]);
for (int i = 1; i <= n; ++i)
for (int j = i + 1; j <= n; ++j)
if (gcd(a[i], a[j]) == 1 && sqr((int)sqrt(sqr(a[i]) + sqr(a[j]))) == sqr(a[i]) + sqr(a[j]))
flow.add(i, j + n, INF), flow.add(j, i + n, INF);
printf("%d\n", ans - flow.dinic() / 2);
}