解题思路:
先利用拓扑排序去掉环中的点,因为环中的点互相保护,永远不可能消灭。然后就是一个裸的最大权闭合子图。如果A保护B,则从B到A连一个容量为INF 的边。如果权值大于0则从原点S到该点连一个容量为权值的边,否则从该点到汇点T连一个容量为该点权值相反数的边。 跑一遍最大流,用所有正权值的和减去最大流。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <map>
#define LL long long
#define FOR(i,x,y) for(int i=x;i<=y;i++)
#define rFor(i,x,y) for(int i=x;i>=y;i--)
using namespace std;
const int maxn = 10000;
const int INF = 0x3f3f3f3f;
struct Edge
{
int from,to,cap,flow;
Edge(int u,int v,int c,int w):from(u),to(v),cap(c),flow(w){ }
};
int n , s , t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void init()
{
for(int i=0;i<=n+1;i++)
G[i].clear();
edges.clear();
}
void AddEdge(int from,int to,int cap)
{
edges.push_back(Edge(from,to,cap,0));
edges.push_back(Edge(to,from,0,0));
int M = edges.size();
G[from].push_back(M-2);
G[to].push_back(M-1);
}
bool BFS()
{
memset(vis,0,sizeof(vis));
queue<int>Q;
Q.push(s);
d[s] = 0;
vis[s] = 1;
while(!Q.empty())
{
int x = Q.front();Q.pop();
for(int i=0;i<G[x].size();i++)
{
Edge& e = edges[G[x][i]];
if(!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x,int a)
{
if(x == t || a == 0) return a;
int flow = 0 , f;
for(int &i = cur[x];i<G[x].size();i++)
{
Edge& e = edges[G[x][i]];
if(d[x] + 1 == d[e.to] && (f = DFS(e.to,min(a,e.cap-e.flow))) > 0)
{
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f;
a -= f;
if(a == 0) break;
}
}
return flow;
}
int Maxflow()
{
int flow = 0;
while(BFS())
{
memset(cur,0,sizeof(cur));
flow += DFS(s,INF);
}
return flow;
}
vector<int>GG[maxn];
int IN[maxn] , VIS[maxn];
int pr[maxn];
int main()
{
int N , M;
while(scanf("%d%d",&N,&M)!=EOF)
{
FOR(i,1,N) GG[i].clear();
memset(IN,0,sizeof(IN));
memset(VIS,0,sizeof(VIS));
int u , v;
FOR(i,1,N)
{
FOR(j,1,M - 1)
{
int u = i * M - M + j + 1;
int v = i * M - M + j;
GG[u].push_back(v);
IN[v]++;
}
}
FOR(i,1,N)
{
FOR(j,1,M)
{
scanf("%d",&pr[i*M - M +j]);
int t,x,y;scanf("%d",&t);
while(t--)
{
scanf("%d%d",&x,&y);
x++;y++;
GG[i * M - M + j].push_back(x * M - M + y);
IN[x * M - M + y]++;
}
}
}
queue<int> Q;
FOR(i,1,N*M) if(!IN[i]) Q.push(i);
while(!Q.empty())
{
int u = Q.front(); Q.pop();
VIS[u] = 1;
int sz = GG[u].size();
for(int i=0;i<sz;i++)
{
int v = GG[u][i];
IN[v] --;
if(!IN[v]) Q.push(v);
}
}
n = N * M + 2 ; s = 0 ; t = n - 1;
init();
FOR(i,1,N)
{
FOR(j,1,M)
{
int u = i * M - M + j;
if(VIS[u])
{
int sz = GG[u].size();
FOR(k,0,sz-1)
{
int v = GG[u][k];
if(VIS[v]) AddEdge(v , u , INF);
}
}
}
}
int sum = 0;
FOR(i,1,N)
{
FOR(j,1,M)
{
int u = i * M - M + j;
if(VIS[u])
{
if(pr[u] > 0) {AddEdge(s , u , pr[u]); sum += pr[u];}
if(pr[u] < 0) AddEdge(u , t , -pr[u]);
}
}
}
int ans = Maxflow();
cout<<sum - ans<<endl;
}
return 0;
}