SOL:最大权闭合子图,记得判环,边拓扑时要反向存,正反的答案不一样。
我们考虑一个环,其每一个点都向中点连边,正向的话中点时判环中的,反向就判在环外了。
#include<bits/stdc++.h> using namespace std; template <class T> #define gc getchar #define sight(c) (‘0‘<=c&&c<=‘9‘) inline void read(T &x){ static int b; static char c; for (b=1,c=gc();!sight(c);c=gc()) if (c==‘-‘) b=-1; for (x=0;sight(c);c=gc()) x=x*10+c-48; x*=b; } struct maxflow{ #define N 100007 #define M 1000007 #define inf (1<<29) #define eho(x) for (int i=head[x];i;i=net[i]) #define Eho(x) for (int &i=hea[x];i;i=net[i]) int n,s,t,head[N],hea[N],net[M],fall[M],tot,gap[N],d[N],cost[M],p[N],be,ed,x,ret; maxflow() {tot=1;memset(head,0,sizeof head);} inline void clear() { tot=1; memset(head,0,sizeof head);} inline void add(int x,int y,int z){ fall[++tot]=y; net[tot]=head[x]; head[x]=tot; cost[tot]=z; } inline void adds(int x,int y,int z){ add(x,y,z); add(y,x,0); } void init() { memset(gap,0,sizeof gap); memset(d,0,sizeof d); ++gap[d[t]=1]; memcpy(hea,head,sizeof hea); p[be=ed=1]=t; while (be<=ed) { x=p[be++]; eho(x) if (!d[fall[i]]) ++gap[d[fall[i]]=d[x]+1],p[++ed]=fall[i]; } } int get(int x,int fl){ if (x==t) return fl; if (!fl) return 0; int flow=0,tmp; Eho(x) if (d[x]==d[fall[i]]+1&&(tmp=get(fall[i],min(fl,cost[i])))) { flow+=tmp; fl-=tmp; cost[i]-=tmp; cost[i^1]+=tmp; if (!fl) return flow; } if (!(--gap[d[x]])) d[s]=n+1; ++gap[++d[x]]; hea[x]=head[x]; return flow; } int isap(int x,int y,int siz){ s=x; t=y; n=siz; init(); ret=get(s,inf); while (d[s]<=n) ret+=get(s,inf); return ret; } }G; #define r(x,y) (x*m+y+1) int n,m,tot,head[N],fall[M],net[M],q[N],be,ed,mp[N],p,x,y,in[N],v[N],sum; inline void add(int x,int y){fall[++tot]=y; net[tot]=head[x]; head[x]=tot; } int main () { // freopen("a.in","r",stdin); read(n); read(m); for(int i=1;i<=n*m;i++) { read(mp[i]); read(p); while (p--) { read(x); read(y); // add(r(x,y),i); in[i]++; add(i,r(x,y)); in[r(x,y)]++; } if (i%m) add(i+1,i),in[i]++; // add(i,i+1),in[i+1]++; } for (int i=n*m;i;i--) if (!in[i]) q[ed++]=i; while (be<ed) { x=q[be++]; v[x]=1; eho(x) if (!(--in[fall[i]])) q[ed++]=fall[i]; } for (int x=1;x<=n*m;x++) if (v[x]){ if (mp[x]>0) G.adds(0,x,mp[x]),sum+=mp[x]; else G.adds(x,n*m+1,-mp[x]); eho(x) if(v[fall[i]]) G.adds(fall[i],x,inf); } printf("%d",sum-G.isap(0,n*m+1,n*m+2)); }