pku 2987
Tuz
posted @ 2009年9月11日 18:14
in acm练习
, 1383 阅读
题目其实是求最大闭合图,将原问题的图转化为最小割模型。
在原图点集合基础上添加源st和汇ed,将原图每条边(u, v)容量设为oo,增加源点st到原图每个正权点v的有向边,容量为node[v],增加原图每个负权点到汇点ed的有向边,容量为-node[v],然后求st到ed的最大流,在残留网络中与源点相连的点为被选择的点,所有正权点权值之和减去最大流为题中所求最大获益,题目权值的绝对值小于10000000,得用long long,呵呵,在这点上WA了一次。
代码:
#include <stdio.h> #include <string.h> #define oo 0x7fffffff #define MAXM 100002 #define MAXN 5005 typedef long long int64; typedef struct { int u; int v; int cap; int next; }edge_t; edge_t e[MAXM]; int first[MAXN]; int node[MAXN]; int dist[MAXN]; int now[MAXN]; int pre[MAXN]; int cnt[MAXN]; int cur[MAXN]; int tot, st, ed, n2, n; int64 sum; void add(int u, int v, int cap) { e[++tot].u = u; e[tot].v = v; e[tot].cap = cap; e[tot].next = first[u]; first[u] = tot; e[++tot].u = v; e[tot].v = u; e[tot].cap = 0; e[tot].next = first[v]; first[v] = tot; } void init() { int i, j, m; scanf("%d %d", &n, &m); memset(first, -1, sizeof(first)); sum = 0; tot = -1; st = 0; ed = n + 1; for(i = 1;i <= n; i++) { scanf("%d", &node[i]); if(node[i] > 0) { add(st, i, node[i]); sum += node[i];} else add(i, ed, -node[i]); } while(m--) { scanf("%d %d", &i, &j); add(i, j, oo); } n2 = n; n += 2; } int64 sap() { int64 tot_flow; int now_flow, found, min; int i, j, t; memset(dist, 0, sizeof(dist)); memset(now, -1, sizeof(now)); memset(cnt, 0, sizeof(cnt)); i = st; tot_flow = 0; now_flow = oo; cnt[0] = n; while(dist[st] < n) { cur[i] = now_flow; found = 0; if(now[i] == -1) t = first[i]; else t = now[i]; while(t != -1) { j = e[t].v; if(e[t].cap > 0 && dist[j] + 1 == dist[i]) { found = 1; now[i] = t; if(e[t].cap < now_flow) now_flow = e[t].cap; pre[j] = t; i = j; if(i == ed) { tot_flow += now_flow; while(i != st) { e[pre[i]].cap -= now_flow; e[pre[i]^1].cap += now_flow; i = e[pre[i]].u; } now_flow = oo; } break; } t = e[t].next; } if(found) continue; if(--cnt[dist[i]] == 0) break; min = n - 1; t = first[i]; while(t != -1) { if(e[t].cap > 0 && dist[e[t].v] < min) { min = dist[e[t].v]; now[i] = t; } t = e[t].next; } dist[i] = min + 1; cnt[dist[i]]++; if(i != st) { i = e[pre[i]].u; now_flow = cur[i]; } } return tot_flow; } void dfs(int u) { int t, v; cnt[u] = 1; t = first[u]; while(t != -1) { v = e[t].v; if(e[t].cap > 0 && cnt[v] == 0) dfs(v); t = e[t].next; } } void solve() { int64 res; int ans, i; res = sap(); memset(cnt, 0, sizeof(cnt)); dfs(st); ans = 0; for(i = 1;i <= n2; i++) ans += cnt[i]; printf("%d %lld\n", ans, sum - res); } int main() { init(); solve(); return 0; }