题目
1565: [NOI2009]植物大战僵尸
Time Limit: 10 Sec Memory Limit: 64 MBDescription
![](http://www.lydsy.com/JudgeOnline/images/1565_1.jpg)
Input
![](http://www.lydsy.com/JudgeOnline/images/1565_2.jpg)
Output
仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。
Sample Input
3 2
10 0
20 0
-10 0
-5 1 0 0
100 1 2 1
100 0
10 0
20 0
-10 0
-5 1 0 0
100 1 2 1
100 0
Sample Output
25
HINT
在样例中, 植物P1,1可以攻击位置(0,0), P2, 0可以攻击位置(2,1)。
一个方案为,首先进攻P1,1, P0,1,此时可以攻击P0,0 。共得到能源收益为(-5)+20+10 = 25。注意, 位置(2,1)被植物P2,0保护,所以无法攻击第2行中的任何植物。
【大致数据规模】
约20%的数据满足1 ≤ N, M ≤ 5;
约40%的数据满足1 ≤ N, M ≤ 10;
约100%的数据满足1 ≤ N ≤ 20,1 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000 。
题解
这道题是最大权闭合子图,求一个最后没有出度的子图。用网络流来做,将所有点之间的边流量为INF,点权为正的连原点,流量为点权,点权为负的连汇点,流量为绝对值。答案为所有正点权和-最大流。但是这道题目还有环保护的问题,一旦环保护了,那么都不可以取,跑最大流会坑!我们要用拓扑排序来处理,最后不断的去掉入度为0的点,得到新的入度为0的点,一些点入度总是不能为0说明在环内,要去掉。这样之后跑最大流就好!【我做的时候拓扑排序思路不是太清晰QAQ
代码
/*Author:WNJXYK*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define Inf 2147483647
#define InfL 10000000000LL
inline void swap(int &x,int &y){int tmp=x;x=y;y=tmp;}
inline void swap(LL &x,LL &y){LL tmp=x;x=y;y=tmp;}
inline int remin(int a,int b){if (a<b) return a;return b;}
inline int remax(int a,int b){if (a>b) return a;return b;}
inline LL remin(LL a,LL b){if (a<b) return a;return b;}
inline LL remax(LL a,LL b){if (a>b) return a;return b;}
const int Maxn=1000;
const int Maxm=500000;
int Ans=0;
struct Edge{
int v,f,nxt;
Edge(){}
Edge(int a,int b,int c){v=a;f=b;nxt=c;}
};
Edge e[Maxm+10];
int head[Maxn+10];
int nume=1;
inline void addEdge(int u,int v,int f){
e[++nume]=Edge(v,f,head[u]);
head[u]=nume;
e[++nume]=Edge(u,0,head[v]);
head[v]=nume;
//printf("MakeEdge %d -> %d : %d\n",u,v,f);
}
int src;
int sink;
queue<int> que;
int dist[Maxn+10];
inline bool bfs(){
while(!que.empty()) que.pop();
memset(dist,-1,sizeof(dist));
que.push(src);
dist[src]=0;
while(!que.empty()){
int now=que.front();
//printf("BFS->%d\n",now);
que.pop();
for (int i=head[now];i;i=e[i].nxt){
//printf("BFS Try->%d\n",e[i].v);
int tp=e[i].v;
if (dist[tp]==-1 && e[i].f!=0){
dist[tp]=dist[now]+1;
que.push(tp);
}
}
}
return dist[sink]!=-1;
}
int dfs(int x,int delta){
int ret=0;
if (x==sink){
return delta;
}else{
for (int i=head[x];i;i=e[i].nxt){
int tp=e[i].v;
if (dist[tp]==dist[x]+1 && e[i].f!=0){
int dd=dfs(tp,remin(delta,e[i].f));
e[i].f-=dd;
e[i^1].f+=dd;
delta-=dd;
ret+=dd;
}
}
}
return ret;
}
inline int dinic(){
int ret=0;
while(bfs())ret+=dfs(src,Inf);
return ret;
}
int n,m;
int score[35][35];
struct MapEdge{
int x,y;
int nxt;
MapEdge(){}
MapEdge(int a,int b,int c){x=a;y=b;nxt=c;}
};
MapEdge me[Maxm+10];
int MapNume=0;
int MapHead[35][35];
int inpoint[35][35];
bool visited[35][35];
inline void addMapEdge(int x,int y,int x1,int y1){
me[++MapNume]=MapEdge(x1,y1,MapHead[x][y]);
MapHead[x][y]=MapNume;
inpoint[x1][y1]++;
}
inline int point2id(int x,int y){
return (x-1)*m+y+1;
}
queue<pair<int,int> > MapQue;
inline void spfaR(int x,int y){
//memset(visited,false,sizeof(visited));
while(!MapQue.empty()) MapQue.pop();
visited[x][y]=true;
MapQue.push(make_pair(x,y));
while(!MapQue.empty()){
int nowx=MapQue.front().first,nowy=MapQue.front().second;
//printf("TopSort->%d %d\n",nowx,nowy);
MapQue.pop();
for (int i=MapHead[nowx][nowy];i;i=me[i].nxt){
int tx=me[i].x,ty=me[i].y;
if (inpoint[tx][ty]<=1){
addEdge(point2id(tx,ty),point2id(nowx,nowy),Inf);
inpoint[tx][ty]--;
visited[tx][ty]=true;
MapQue.push(make_pair(tx,ty));
}else{
addEdge(point2id(tx,ty),point2id(nowx,nowy),Inf);
inpoint[tx][ty]--;
}
}
}
}
inline void solveRoundP(){
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
if (inpoint[i][j]<=0 && visited[i][j]==false){
spfaR(i,j);
}
}
}
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
if (inpoint[i][j]<=0){
if (score[i][j]>=0){
addEdge(src,point2id(i,j),score[i][j]);
Ans+=score[i][j];
}else{
addEdge(point2id(i,j),sink,-score[i][j]);
}
}
///Arrest
//if (inpoint[i][j]==0)
//printf("UsePoint->%d %d\n",i,j);
}
}
}
int main(){
//freopen("pvz.in","r",stdin);
//freopen("pvz.out","w",stdout);
scanf("%d%d",&n,&m);
src=1;
sink=n*m+2;
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
if (j>1) addMapEdge(i,j,i,j-1);
scanf("%d",&score[i][j]);
int w;
scanf("%d",&w);
for (int k=1;k<=w;k++){
int x,y;
scanf("%d%d",&x,&y);
x++;y++;
if (x!=i || y!=j-1)
addMapEdge(i,j,x,y);
}
}
}
solveRoundP();
printf("%d\n",Ans-dinic());
return 0;
}