1、题意:有一些点,点与点之间有保护关系,每个点都有一个权值,求能获得的最大值
2、分析:裸的最大权闭合图,用网络流进行求解,然后我们发现点与点之间的保护关系可能构成环,这样网络流是无法处理的,然后我们拓扑排序去掉那些不能获得的点。注意!!!!这里的环是不能用强连通来强行去掉的,因为——比如有一个点,他两端与它相连的点在环内,那么这个点你也去不掉
最大权闭合图模型:建立源点s和汇点t,将所有正权点连向s,容量为点权,将所有负权点连向t,容量为点权的相反数,原图中的边容量全部设成inf,跑一边最小割,用所有正权点的总和减一下就是答案了
#include <queue> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; #define M 500010 #define inf 214748364 inline int read(){ char ch = getchar(); int x = 0, f = 1; while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while('0' <= ch && ch <= '9'){ x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } namespace dinic{ struct Edge{ int from, to, cap, flow, next; } G[M]; int head[M], cur[M], tot; int vis[M], d[M]; int s, t; inline void init(){ tot = -1; memset(head, -1, sizeof(head)); } inline void add(int u, int v, int w){ G[++ tot] = (Edge){u, v, w, 0, head[u]}; head[u] = tot; G[++ tot] = (Edge){v, u, 0, 0, head[v]}; head[v] = tot; } inline bool BFS(){ memset(vis, 0, sizeof(vis)); queue<int> Q; Q.push(s); vis[s] = 1; d[s] = 0; while(!Q.empty()){ int x = Q.front(); Q.pop(); for(int i = head[x]; i != -1; i = G[i].next){ Edge& e = G[i]; if(e.cap > e.flow && !vis[e.to]){ vis[e.to] = 1; d[e.to] = d[x] + 1; Q.push(e.to); } } } return vis[t]; } inline int DFS(int x, int a){ if(x == t || a == 0) return a; int flow = 0, f; for(int &i = cur[x]; i != -1; i = G[i].next){ Edge& e = G[i]; if(d[e.to] == d[x] + 1 && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0){ e.flow += f; G[i ^ 1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } inline int ans(){ int flow = 0; while(BFS()){ for(int i = s; i <= t; i ++) cur[i] = head[i]; flow += DFS(s, inf); } return flow; } } int val[M]; struct Edge{ int u, v, next; } G[M]; int head[M], tot; int du[M], ok[M]; int n, m; inline void addedge(int u, int v){ // printf("%d %d\n", u, v); G[++ tot] = (Edge){u, v, head[u]}; head[u] = tot; du[v] ++; } inline void toposort(){ queue<int> Q; for(int i = 1; i <= n * m; i ++) if(!du[i]){ Q.push(i); ok[i] = 1; } while(!Q.empty()){ int x = Q.front(); Q.pop(); for(int i = head[x]; i != -1; i = G[i].next){ du[G[i].v] --; if(!du[G[i].v]){ Q.push(G[i].v); ok[G[i].v] = 1; } /*puts("fuck"); printf("%d\n", i);*/ } } } int main(){ n = read(), m = read(); #define Num(i, j) (i - 1) * m + j memset(head, -1, sizeof(head)); for(int i = 1; i <= n; i ++){ for(int j = 1; j <= m; j ++){ int num = Num(i, j); val[num] = read(); int op = read(); for(int k = 1; k <= op; k ++){ int x = read(), y = read(); x ++; y ++; addedge(num, Num(x, y)); } if(j != m) addedge(num + 1, num); } } toposort(); //puts("fuck"); dinic::s = 0; dinic::t = n * m + 1; dinic::init(); int res = 0; for(int i = 1; i <= n * m; i ++) if(ok[i]){ if(val[i] > 0) res += val[i], dinic::add(dinic::s, i, val[i]); else dinic::add(i, dinic::t, -val[i]); for(int j = head[i]; j != -1; j = G[j].next){ if(ok[G[j].v]){ dinic::add(G[j].v, i, inf); } } } printf("%d\n", res - dinic::ans()); return 0; }