BZOJ3158: 千钧一发

bzoj3158

题目描述

image

思路

很显然,当两个点之间两个条件都不满足,那么这两个点不能共存。但这样连出来的边不一定是二分图,不能直接用最大权闭合子图来解决。

则考虑拆点来构造二分图并互相连边,最后答案除以二即可。

关于最大权闭合子图戳这里 最小割的一些理解和应用

代码

#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);
}

猜你喜欢

转载自www.cnblogs.com/erro/p/9038244.html