AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1565
这题看上去并不会做,结果又是最大权闭合子图的裸题。
于是就去看了一发论文,明白建图的技巧。
论文地址:《最小割模型在信息学竞赛中的应用》
嗯,讲这个的部分在第三章。
好了,看完论文就知道DAG的怎么搞了。
这题可能有环,因为环上的不能选,有边连到环上[被环上的点保护着的]的也不能选。
那么我们就把环弄掉,连在环上的呢?用反图,然后拓扑排序就可以同时把这两种点排除掉了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=32; const int maxt=610; const int INF=0x3f3f3f3f; struct Node{ int data,next,low; }node[maxt*maxt*2]; #define now node[point].data #define then node[point].next #define www node[point].low struct Edge{ int u,v; }edge[maxt*maxt]; int n,m,tot,cnt; int s,t,Idex,ans; int indeg[maxt],stack[maxt],top; int head[maxt],cur[maxt]; int dis[maxt],que[maxt]; int val[maxn][maxn],ind[maxn][maxn]; bool used[maxt]; void add1(int u,int v){ node[cnt].data=v;node[cnt].next=head[u];head[u]=cnt++;indeg[v]++; edge[cnt].u=v,edge[cnt].v=u; } void add(int u,int v,int w){ node[cnt].data=v;node[cnt].next=head[u];node[cnt].low=w;head[u]=cnt++; node[cnt].data=u;node[cnt].next=head[v];node[cnt].low=0;head[v]=cnt++; } bool BFS(){ memset(dis,-1,sizeof(dis)); int H=0,T=1;dis[0]=0; while(H<T){ H++; for(int point=head[que[H]];point!=-1;point=then) if(www && dis[now]<0){ dis[now]=dis[que[H]]+1; que[++T]=now; } } return dis[t]>0; } int dfs(int x,int low){ if(x==t) return low; int Low; for(int &point=cur[x];point!=-1;point=then) if(www && dis[now]==dis[x]+1){ Low=dfs(now,min(low,www)); if(Low){ www-=Low;node[point^1].low+=Low; return Low; } } return 0; } int main(){ #ifndef ONLINE_JUDGE freopen("1565.in","r",stdin); freopen("1565.out","w",stdout); #endif int x,y,k; scanf("%d%d",&n,&m); t=n*m+1; for(int i=1;i<t;i++) head[i]=-1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ind[i][j]=++Idex; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%d%d",&val[i][j],&k); while(k--){ scanf("%d%d",&x,&y); x++,y++; add1(ind[i][j],ind[x][y]); } if(j!=1) add1(ind[i][j],ind[i][j-1]); } for(int i=1;i<t;i++) if(!indeg[i]) stack[++top]=i; while(top){ k=stack[top--],used[k]=true; for(int point=head[k];point!=-1;point=then) if(--indeg[now]==0) stack[++top]=now; } tot=cnt;cnt=0; for(int i=s;i<=t;i++) head[i]=-1; for(int i=1;i<=tot;i++) if(used[edge[i].u] && used[edge[i].v]) add(edge[i].u,edge[i].v,INF); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(used[ind[i][j]]){ if(val[i][j]>0) add(s,ind[i][j],val[i][j]),ans+=val[i][j]; else if(val[i][j]<0) add(ind[i][j],t,-val[i][j]); } int flag; while(BFS()){ memcpy(cur,head,sizeof(cur)); while(flag=dfs(s,INF)) ans-=flag; } printf("%d",ans); return 0; }