首页 > 代码库 > CSU 1319 CX‘s dreams 最大权闭合图 求最多的正点权个数
CSU 1319 CX‘s dreams 最大权闭合图 求最多的正点权个数
题目链接:点击打开链接
思路:
显然就是问最大权闭合图 和 能取最多的正点权个数
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]; else F.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 3 2 3 5 -2 -3 -5 2 1 2 2 1 2 1 3 3 3 0 0 0 -1 -10 -10 2 1 2 2 1 2 3 3 2 1 */
CSU 1319 CX‘s dreams 最大权闭合图 求最多的正点权个数
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。