CSU 1319 CX‘s dreams 最大权闭合图 求最多的正点权个数

来源:互联网 发布:所以木工软件 编辑:程序博客网 时间:2024/05/22 13:48

题目链接:点击打开链接

思路:

显然就是问最大权闭合图 和 能取最多的正点权个数

1、首先对于正权值的付出,直接取,而对于梦想也忽略正权值的付出,这样就转成一个裸的最大权闭合图了。

2、计算此时的正点权个数:把所有点权*大数C,然后把正点权值+1,跑出来流量就是 flow / C, 最多的正点权个数就是 正点权点集-flow%C.


#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>using namespace std;//点标 [0,n]typedef long long ll;const int N = 3010;const int M = 500010;const ll INF = 1e18;template<class T>struct Max_Flow {    int n;    int Q[N], sign;    int head[N], level[N], cur[N], pre[N];    int nxt[M], pnt[M], E;    T cap[M];    void Init(int n) {        this->n = n+1;        E = 0;        std::fill(head, head + this->n, -1);    }    //有向rw 就= 0    void add(int from, int to, T c, T rw) {        pnt[E] = to;        cap[E] = c;        nxt[E] = head[from];        head[from] = E++;        pnt[E] = from;        cap[E] = rw;        nxt[E] = head[to];        head[to] = E++;    }    bool Bfs(int s, int t) {        sign = t;        std::fill(level, level + n, -1);        int *front = Q, *tail = Q;        *tail++ = t; level[t] = 0;        while(front < tail && level[s] == -1) {            int u = *front++;            for(int e = head[u]; e != -1; e = nxt[e]) {                if(cap[e ^ 1] > 0 && level[pnt[e]] < 0) {                    level[pnt[e]] = level[u] + 1;                    *tail ++ = pnt[e];                }            }        }        return level[s] != -1;    }    void Push(int t, T &flow) {        T mi = INF;        int p = pre[t];        for(int p = pre[t]; p != -1; p = pre[pnt[p ^ 1]]) {            mi = std::min(mi, cap[p]);        }        for(int p = pre[t]; p != -1; p = pre[pnt[p ^ 1]]) {            cap[p] -= mi;            if(!cap[p]) {                sign = pnt[p ^ 1];            }            cap[p ^ 1] += mi;        }        flow += mi;    }    void Dfs(int u, int t, T &flow) {        if(u == t) {            Push(t, flow);            return ;        }        for(int &e = cur[u]; e != -1; e = nxt[e]) {            if(cap[e] > 0 && level[u] - 1 == level[pnt[e]]) {                pre[pnt[e]] = e;                Dfs(pnt[e], t, flow);                if(level[sign] > level[u]) {                    return ;                }                sign = t;            }        }    }    T Dinic(int s, int t) {        pre[s] = -1;        T flow = 0;        while(Bfs(s, t)) {            std::copy(head, head + n, cur);            Dfs(s, t, flow);        }        return flow;    }};Max_Flow <ll>F;ll dream[N], work[N], ans;int from, to;int n, m;const ll C = 1e6;void input(){ans = 0;from = 0; to = n+m+1;F.Init(to);for(int i = 1; i <= n; i++){scanf("%lld", &dream[i]);F.add(from, i, dream[i]*C+1LL, 0);ans += dream[i];}for(int i = 1; i <= m; i++){scanf("%lld", &work[i]);if(work[i] >= 0) ans += work[i];elseF.add(n +i, to, -work[i]*C, 0);}for(int i = 1, siz, u; i <= n; i++){scanf("%d", &siz);while(siz--){scanf("%d", &u);if(work[u] >= 0)continue;F.add(i, n+u, INF, 0);}}}int main() {while(~scanf("%d %d", &n, &m)){input();ll flow = F.Dinic(from,to);//cout<<"FLOW:"<<flow<<endl;cout<< ans - flow / C << " " << n-flow % C <<endl;}return 0;}/*3 32 3 5-2 -3 -52 1 22 1 21 33 30 0 0-1 -10 -102 1 22 1 23 3 2 1*/


0 0