P1361 小M的作物(最小割好题)

传送门

题目大意:给我们一些节点,我们需要把这些节点分为两部分,节点位于两种区域中的价值不同,而且

还会有一些组合,这些组合位于不同的区域中价值也不同。

思路:本蒟蒻没想出来....看的题解。

印象比较深刻的话:最小割在数值上与最大流相等,但在本身性质上与网络流无任何关系。

我的理解(可能会很抽象....):最小割可以抽象为两个对立的势力一样,要么位于A,要么位于B,位于A有一定的

好处,位于B也有一定的好处,而我们把这些好处当作容量连边,把x想象成节点,连边A->x,权值为加入

A的好处,然后连边x->B,权值设置为加入B的好处,这样跑最大流,虽然用的最大流算法,但是得到的却是x位于A,B中的最小那个权值

也就是最小割,然后我们把所有节点位于A,B的权值和-最小割,就是权值最大的安排。

然后组合呢?其实这题的组合也可以是一个节点x,我们只需要把组合也虚拟为两个节点,然后A与其中一个节点连边,

权值设置为组合在A下的得分,再将该节点与组合中的节点连边,大小设置为inf,同理,我们再把另一个节点与B连边,

权值设置为B下的得分,再把组合中的节点与其连边,权值设置为inf,这样也就把组合也抽象为了两种对立的势力下的得分。

假设这题的组合不是一个组合在A,B下同时有得分,列如组合(1,2,3)只有在A下的得分x1,组合(2,3,4)只有在B下的得分x2,这样

就样就没法形成对立的势力,没法用最小割解决(大概),口胡结束.

本蒟蒻刚开始接触网络流,欢迎巨佬指点我错误的地方^_^

不好意思,只知道自己理解了,忘记提交了,结果有个小错误,已改正。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 600005;
const int inf = 0x3f3f3f3f;
struct edge {
    int f, t, nxt;
    ll flow;
}e[maxn * 2];
int hd[maxn], tot = 1;
void add(int f, int t, ll flow) {
    e[++tot] = { f,t,hd[f],flow };
    hd[f] = tot;
}
int n, m, c1, c2;
int s, d;
int dep[maxn], cur[maxn];
bool bfs() {//找增广路
    memset(dep, 0, sizeof(dep));
    dep[s] = 1;
    queue<int>Q;
    Q.push(s);
    while (!Q.empty()) {
        int u = Q.front(); Q.pop();
        for (int i = hd[u]; i; i = e[i].nxt) {
            int v = e[i].t, flow = e[i].flow;
            if (flow > 0 && !dep[v]) {
                dep[v] = dep[u] + 1;
                if (v == d)return true;
                Q.push(v);
            }
        }
    }
    return false;
}
ll dfs(int u, ll flow) {
    if (u == d)return flow;
    ll last = flow;
    for (int i = cur[u]; i; i = e[i].nxt) {
        cur[u] = i;//当前弧优化
        int v = e[i].t; ll flow = e[i].flow;
        if (flow > 0 && dep[v] == dep[u] + 1) {
            ll tmp = dfs(v, min(last, flow));
            last -= tmp;
            e[i].flow -= tmp;
            e[i ^ 1].flow += tmp;
            if (last == 0)break;//流量没了直接退出循环,与当前弧优化对应
        }
    }
    if (last == flow)dep[u] = 0;//从当前点一点流量没流到终点(未找到增广路),炸点优化
    return flow - last;//返回剩余流量
}
ll dinic() {
    ll maxflow = 0;
    while (bfs()) {
        memcpy(cur, hd, sizeof(hd));
        maxflow += dfs(s, inf);
    }
    return maxflow;
}
int main() {
    //freopen("test.txt", "r", stdin);
    scanf("%d", &n);
    ll sum = 0;
    s = n + 1, d = n + 2;
    for (int i = 1; i <= n; i++) {
        ll x; scanf("%lld", &x); sum += x;
        add(s, i, x),add(i, s, 0);
    }
    for (int i = 1; i <= n; i++) {
        ll x; scanf("%lld", &x); sum += x;
        add(i, d, x); add(d, i, 0);
    }
    scanf("%d", &m);
    for (int i = 1; i <= m; i++) {
        int t;ll wa, wb; scanf("%d%lld%lld", &t, &wa, &wb);
        sum += wa + wb;
        add(s, n + 2 + i, wa), add(n + 2 + i, s, 0);//拆点连边
        add(n + 2 + m + i, d, wb), add(d, n + 2 + m + i, 0);
        for (int k = 1; k <= t; k++) {
            int x; scanf("%d", &x);
            add(n + 2 + i, x, inf), add(x, n + 2 + i, 0);
            add(x, n + 2 + m + i, inf), add(n + 2 + m + i, x, 0);
        }
    }
    ll mincut = dinic();
    printf("%lld\n", sum - mincut);
    return 0;
}

 

posted @ 2021-04-05 11:25  cono奇犽哒  阅读(62)  评论(0)    收藏  举报