题目大意请自便。
经典的最大权闭合子图。不过要拓扑一下图的反向边去环,因为如果不反向那删掉的点是环内的点和保护环的点,但明显保护环的点是可以取到的,而真正因该去掉的被环保护的点却还存在,所以必须反向。然后就可以按照经典建图方法搞就好了。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#define INF 10000000
using namespace std;
struct atp
{
int y,d,next,op;
} e[1000000],e2[1000000];
int now=0,tot=0,tot2=0,n,m,s,t,N=0,sum=0;
int score[1000],attack[1000],first[1000],first2[1000];
int a[200][200];
int h[1000],num[1000];
bool b[1000];
int Ins(int x,int y)
{
tot++;
e[tot].y=y;
e[tot].next=first[x];
first[x]=tot;
return 0;
}
int add(int x,int y,int d)
{
tot2++;
e2[tot2].y=y;
e2[tot2].d=d;
e2[tot2].next=first2[x];
e2[tot2].op=tot2+1;
first2[x]=tot2;
tot2++;
e2[tot2].y=x;
e2[tot2].d=0;
e2[tot2].next=first2[y];
e2[tot2].op=tot2-1;
first2[y]=tot2;
return 0;
}
void init()
{
scanf("%d%d",&n,&m);
for (int i=0;i<n;i++)
for (int j=0;j<m;j++) a[i][j]=++now;
for (int i=0;i<n;i++)
for (int j=0;j<m;j++)
{
int num,x,y;
scanf("%d%d",&score[a[i][j]],&num);
for (int k=0;k<num;k++)
{
scanf("%d%d",&x,&y);
attack[a[x][y]]++;
Ins(a[i][j],a[x][y]);
}
}
for (int i=0;i<n;i++)
for (int j=0;j<m-1;j++)
{
attack[a[i][j]]++;
Ins(a[i][j+1],a[i][j]);
}
}
int topsort()
{
queue<int> q;
memset(b,0,sizeof(b));
for (int i=1;i<=now;i++)
if (attack[i]==0)
{
q.push(i);
b[i]=1;
}
while (!q.empty())
{
int u=q.front();
q.pop();
for (int p=first[u];p;p=e[p].next)
{
// attack[e[p].y]--;
if (--attack[e[p].y]==0)
q.push(e[p].y),b[e[p].y]=1;
}
}
return 0;
}
int find(int u,int flow)
{
if (u==t) return flow;
int temp=flow,pos=N-1;
for (int p=first2[u];p;p=e2[p].next)
{
if (h[u]==h[e2[p].y]+1 && e2[p].d>0)
{
int f=find(e2[p].y,min(e2[p].d,temp));
temp-=f;
e2[p].d-=f;
e2[e2[p].op].d+=f;
if (temp==0 || h[s]==N) return flow-temp;
}
if (e2[p].d>0 && pos>h[e2[p].y]) pos=h[e2[p].y];
}
if (temp==flow)
{
num[h[u]]--;
if (num[h[u]]==0) h[s]=N;
else
{
h[u]=pos+1;
num[h[u]]++;
}
}
return flow-temp;
}
int work()
{
topsort();
s=0;t=n*m+1;
for (int i=1;i<=now;i++)
{
if (b[i] && score[i]>0) add(s,i,score[i]),sum+=score[i];
if (b[i] && score[i]<0) add(i,t,-score[i]);
}
for (int i=1;i<=now;i++)
if (b[i])
for (int p=first[i];p;p=e[p].next)
if (b[e[p].y])
add(e[p].y,i,INF);
for (int i=1;i<=now;i++) N++;
N+=2;
num[0]=N;
int ans=0;
while (h[s]<N) ans+=find(s,INF);
printf("%d\n",ans>0?sum-ans:0);
return ans;
}
int main()
{
init();
work();
return 0;
}