Firing
http://poj.org/problem?id=2987
知识点:1.最大权闭合子图
2.关于统计留下多少个人:dfs查询每条边是否满流,满流就留下来了(灵活运用跑完网络流留下来的残留图)
#include <iostream> #include <cstdio> #include <queue> #include <cstring> #define int long long using namespace std; int n,m; int f[5010]; struct edge { int to; int nxt; int len; }e[60010 << 1]; int head[60010],cnt = 1; void add(int x,int y,int len) { e[++cnt].nxt = head[x]; e[cnt].to = y; e[cnt].len = len; head[x] = cnt; } int S = 5100,T = 5120; int psum = 0; int deep[6010]; queue <int> q; int bfs() { memset(deep,0,sizeof(deep)); deep[S] = 1; q.push(S); while(!q.empty()) { int u = q.front(); q.pop(); for(int i = head[u];i;i = e[i].nxt) { int np = e[i].to; if(deep[np] == 0 && e[i].len) { deep[np] = deep[u] + 1; q.push(np); } } } if(deep[T] == 0)return 0; else return 1; } int dfs(int t,int minn) { if(t == T) return minn; int tans = 0; for(int i = head[t];i;i = e[i].nxt) { if(e[i].len) { int np = e[i].to; if(deep[np] == deep[t] + 1) { int he1 = dfs(np,min(e[i].len,minn)); if(he1) { tans += he1; minn -= he1; e[i].len -= he1; e[i^1].len += he1; if(minn == 0)break; } } } } return tans; } int vis[100010]; int dfs(int u){ int ans = 1; vis[u] = 1; for(int i = head[u];i;i = e[i].nxt) { int v = e[i].to; if(e[i].len > 0&& !vis[v]) { ans+=dfs(v); } } return ans; } signed main() { scanf("%lld%lld",&n,&m); for(int i = 1;i <= n;i++) scanf("%lld",&f[i]); int x,y; while(m--) { scanf("%lld%lld",&x,&y); add(x,y,2147483640),add(y,x,0); } for(int i = 1;i <= n;i++) { if(f[i] > 0)psum += f[i]; if(f[i] > 0)add(S,i,f[i]),add(i,S,0); else if(f[i] < 0)add(i,T,-f[i]),add(T,i,0); } int ret = 0; while(bfs()) { ret += dfs(S,999999999); } printf("%lld %lld",dfs(S) - 1,psum - ret); return 0; }