洛谷 P2805 [NOI2009]植物大战僵尸
题解 :
将被保护的向保护的的点连边建图,然后跑最大闭合子图,
注意的点, 1.每一行后面的点会保护前面的点 2.会存在环,需要先在反图跑一个拓扑图去环和环上直接或间接保护的点。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000;
const int maxm = 3e6+10;
const int INF = 0x3f3f3f3f;
int n,m,tot;
int l[maxn],h[maxn],cur[maxn];
struct edge
{
int to, c, next;
edge(int to = 0, int c = 0, int next = 0) : to(to) ,c(c), next(next) {}
}es[maxm];
void add_edge(int u , int v, int c)
{
es[tot] = edge(v,c,h[u]); h[u] = tot++;
es[tot] = edge(u,0,h[v]); h[v] = tot++;
//cout << u << " " << v << " " << c << endl;
}
bool bfs(int s, int t)
{
memset(l,0,sizeof(l));
l[s] = 1;
queue <int> Q;
Q.push(s);
while(!Q.empty())
{
int u = Q.front();Q.pop();
if(u == t) return true;
for(int i = h[u]; ~i; i = es[i].next)
{
int v = es[i].to;
if(es[i].c && !l[v]) {l[v] = l[u] + 1; Q.push(v);}
}
}
return false;
}
int dfs(int x, int t, int mf)
{
if(x == t) return mf;
int ret = 0;
for(int &i = cur[x]; ~i; i = es[i].next)
{
int v = es[i].to;
if(es[i].c && l[v] == l[x] + 1)
{
int f = dfs(v,t,min(es[i].c, mf-ret));
es[i].c -= f;
es[i^1].c += f;
ret += f;
if(ret == mf) return ret;
}
}
return ret;
}
int dinic(int s,int t)
{
int res = 0;
while(bfs(s,t))
{
for(int i = 0; i <= t; i++) cur[i] = h[i];
res += dfs(s,t,INF);
}
return res;
}
int sum=0;
int sc[maxn];
int vis[maxn];
int d[maxn];
vector <int> G[maxn];
void tuopu()
{
queue<int> q;
for(int i = 1; i <= n; i++)
if(d[i] == 0) q.push(i);
while(!q.empty())
{
int u = q.front(); q.pop(); vis[u] = true;
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
d[v]--;
if(!d[v]) q.push(v);
}
}
}
int main()
{
tot = 0;
memset(d,0,sizeof(d));
memset(h,-1,sizeof(h));
memset(vis,false,sizeof(vis));
int r,c;
scanf("%d%d",&r,&c);
int s = 0, t = r*c+1;
n = r*c;
for(int i = c; i > 1; i--)
for(int j = 1; j <= r; j++)
{
int u = (j-1)*c + i, v= (j-1)*c + i-1;
G[u].push_back(v);
d[v]++;
}
for(int i = 1; i <= r*c; i++)
{
int w;
scanf("%d%d",&sc[i],&w);
for(int j = 1; j <= w; j++)
{
int ri,ci;
scanf("%d%d",&ri,&ci);
G[i].push_back(ri*c+ci+1);
d[ri*c+ci+1] ++;
}
}
tuopu();
//for(int i = 1; i <= n; i++)
// if(vis[i]) cout << i << "**";
//cout <<"*"<<endl;
for(int i = 1; i <= n; i++)
if(vis[i])
{
if(sc[i] < 0) add_edge(i,t,-sc[i]);
else add_edge(s,i,sc[i]),sum += sc[i];
for(int j = 0; j < G[i].size(); j++)
if(vis[G[i][j]]) add_edge(G[i][j],i,INF);
}
// cout << sum << endl;
int ans = sum - dinic(s,t);
printf("%d\n",ans);
return 0;
}