Description
题解:
经典的最大权闭合子图模型,不会的可以去网上查找相关资料,挺简单的。这道题呢,对于植物i可以保护植物j,我们可以建一条j->i的有向边(注意同一行相邻2个植物也有保护关系),然后跑一次Tarjan,因为在一个环中的植物我们是不能选到的,对于这些不能选到的植物,我的处理方法是将他们的权值看做负无穷,然后其他的按照最大权闭合子图搞就行了。
代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
const int inf=2147483647;
const int Maxn=35;
const int Max=910;
struct Edge1{int y,next;}E[400000];
struct Edge2{int y,d,next;}e[2110000];
int score1[Maxn][Maxn],score2[Max],num[Maxn][Maxn],z=0;
int n,m;
int last[Max],len=1;
int Last[Max],Len=0;
int dfn[Max],low[Max],id=0,bel[Max],cnt=0,sta[Max],top=0,p[Max];
bool in[Max],vis[Max],hh[Max][Max];
void ins(int x,int y,int d)
{
int t=++len;
e[t].y=y;e[t].d=d;
e[t].next=last[x];last[x]=t;
}
void addedge(int x,int y,int d){ins(x,y,d);ins(y,x,0);}
void Ins(int x,int y)
{
int t=++Len;
E[t].y=y;E[t].next=Last[x];Last[x]=t;
}
void Tarjan(int x)
{
low[x]=dfn[x]=++id;
sta[++top]=x;in[x]=true;
for(int i=Last[x];i;i=E[i].next)
{
int y=E[i].y;
if(!dfn[y])Tarjan(y),low[x]=min(low[x],low[y]);
else if(in[y])low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x])
{
int i;cnt++;
do
{
i=sta[top--];
bel[i]=cnt;
p[cnt]++;
in[i]=false;
}while(i!=x);
}
}
queue<int>q;
int h[Max],st,ed;
bool bfs()
{
memset(h,0,sizeof(h));h[st]=1;
q.push(st);
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=last[x];i;i=e[i].next)
if(e[i].d&&!h[e[i].y])h[e[i].y]=h[x]+1,q.push(e[i].y);
}
return h[ed];
}
int dfs(int x,int f)
{
if(x==ed)return f;
int s=0,t;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(h[y]==h[x]+1&&e[i].d&&s<f)
{
t=dfs(y,min(f-s,e[i].d));
s+=t;e[i^1].d+=t;e[i].d-=t;
}
}
if(s==0)h[x]=0;
return s;
}
int main()
{
int ans=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
num[i][j]=++z;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int k;
scanf("%d%d",&score1[i][j],&k);
for(int l=1;l<=k;l++)
{
int x,y;
scanf("%d%d",&x,&y);x++;y++;
Ins(num[x][y],num[i][j]);
hh[num[x][y]][num[i][j]]=true;
}
if(j>1&&!hh[num[i][j-1]][num[i][j]])Ins(num[i][j-1],num[i][j]);
}
for(int i=1;i<=z;i++)if(!dfn[i])Tarjan(i);
st=z+1;ed=z+2;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int x=num[i][j];
if(p[bel[x]]>1)addedge(x,ed,inf);
else if(score1[i][j]<0)addedge(x,ed,-score1[i][j]);
else ans+=score1[i][j],addedge(st,x,score1[i][j]);
memset(vis,false,sizeof(vis));vis[x]=true;
for(int l=Last[x];l;l=E[l].next)
{
int y=E[l].y;
if(vis[y])break;vis[y]=true;
addedge(x,y,inf);
}
}
while(bfs())ans-=dfs(st,inf);
printf("%d",ans);
}