题目
可以发现,这个题就是在有一堆某个植物要在某个植物之前吃的要求下求最大值。
如果依赖关系是棵树,可以树形DP。
如果依赖关系是个DAG,可以做最大权闭合子图。
具体来说,最大权闭合子图的求解是在网络流二元关系下实现的。
具体关系为某一个吃了后面的某一个没吃就不合法,代价为inf。
于是可以用inf流量的边将他们相连,正收益的与S相连,正代价的与T相连,将正收益全部相加-最小割(正代价+需要失去的正收益)就是答案。
AC Code:
#include<bits/stdc++.h>
#define maxn 601
#define maxm maxn*maxn*4
#define inf 0x3f3f3f3f
#define LL long long
using namespace std;
char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
void read(int &res)
{ char ch;bool f=0;for(;!isdigit(ch=getc());) if(ch=='-') f=1;
for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
(f) && (res = -res);}
int n,m,sc[maxn];
vector<int>G[maxn];
inline int id(int a,int b){ return (a-1)*m+b; }
int dfn[maxn],low[maxn],c[maxn],siz[maxn],sum[maxn],tot,scc;
int sta[maxn],tp;
void dfs(int now)
{
dfn[now] = low[now] = ++tot;
sta[tp++] = now;
for(int i=0,siz=G[now].size(),v;i<siz;i++)
if(!dfn[v=G[now][i]]) dfs(v),low[now]=min(low[now],low[v]);
else if(!c[v]) low[now] = min(low[now],dfn[v]);
if(low[now]==dfn[now])
{
scc++;
for(int tmp=-1;tmp!=now;)
c[tmp=sta[--tp]]=scc,
siz[scc]++,
sum[scc]+=sc[tmp];
if(siz[scc] > 1)
sum[scc] = -inf;
}
}
int S,T,h[maxn],gap[maxn];
int buf[maxn],info[maxn],Prev[maxm],to[maxm],cap[maxm],cnt_e=1;
void Node(int u,int v,int c){Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cap[cnt_e]=c;}
void Line(int u,int v,int c){ Node(u,v,c),Node(v,u,0); }
/*
int aug(int now,int Max)
{
if(now == T) return Max;
int inc , st = Max;
for(int &i=info[now];i;i=Prev[i])
if(cap[i] && h[to[i]]+1 == h[now])
{
inc = aug(to[i],min(st,cap[i]));
st-=inc,cap[i]-=inc,cap[i^1]+=inc;
if(!st || h[S]>T) return Max-st;
}
if(!--gap[h[now]]) h[S] = T+1;
++gap[++h[now]];info[now]=buf[now];
return Max-st;
}*/
int aug(int now,int Max){
if(now == T) return Max;
int inc,st=Max;
for(int &i=info[now];i;i=Prev[i])if(cap[i]&&h[to[i]]+1==h[now]){
inc=aug(to[i],min(cap[i],st));
if(inc) st-=inc,cap[i]-=inc,cap[i^1]+=inc;
else h[to[i]]=-1;
if(!st) break;
}
return Max-st;
}
bool BFS()
{
static int q[maxn],L,R;
memset(h,-1,sizeof h);
h[q[L=R=0]=T]=0,R++;
for(int now;L<R;)
{ now = q[L++];
for(int i=info[now];i;i=Prev[i])
if(cap[i^1]&&h[to[i]]==-1)
h[q[R++]=to[i]]=h[now]+1;
}
return h[S] != -1;
}
int main()
{
//freopen("1.in","r",stdin);
read(n),read(m);
for(int i=1,x;i<=n;i++)
for(int j=1;j<=m;j++){
read(sc[id(i,j)]),read(x);
for(int u,v;x--;)
read(u),read(v),u++,v++,G[id(u,v)].push_back(id(i,j));
if(j<m) G[id(i,j)].push_back(id(i,j+1));
}
for(int i=1;i<=n*m;i++)
if(!dfn[i])
dfs(i);
S = scc+1 , T = scc+2;
int ans = 0;
for(int i=1;i<=scc;i++)
{
if(sum[i] > 0) Line(S,i,sum[i]),ans+=sum[i];
else if(sum[i] < 0)Line(i,T,-sum[i]);
//printf("%d\n",sum[i]);
}
for(int i=1;i<=n*m;i++)
for(int j=0,siz=G[i].size(),v;j<siz;j++)
if(c[v=G[i][j]] != c[i])
{
//printf("%d %d\n",c[i],c[v]);
Line(c[i],c[v],inf);
}
//printf("%d\n",ans);
memcpy(buf,info,sizeof info);
for(;BFS();)
{
ans -= aug(S,inf);
memcpy(info,buf,sizeof buf);
if(ans < 0){ ans = 0;break; }
}
printf("%d\n",ans);
}