bzoj 3996 线性代数 —— 最大权闭合子图
Posted zinn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3996 线性代数 —— 最大权闭合子图相关的知识,希望对你有一定的参考价值。
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3996
把题中的式子拆开看看,发现就是如下关系:
如果 a[i] == 1 && a[j] == 1,则 b[i][j] 有贡献;
如果 a[i] == 1,则 -c[i] 有贡献;
所以就是最大权闭合子图的模型,b[i][j] 向 a[i] 和 a[j] 连边,a[i] 向 c[i] 连边;
而 c[i] 这个点实际上没什么用,直接变成 a[i] 向 T 连边,边权是 c[i] 即可。
代码如下:
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; int const xn=300005,xm=(xn<<3),inf=0x3f3f3f3f; int n,hd[xn],ct,to[xm],nxt[xm],c[xm],S,T,dis[xn],cur[xn]; queue<int>q; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=0; ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘)ret=ret*10+ch-‘0‘,ch=getchar(); return f?ret:-ret; } void ade(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct; c[ct]=z;} void add(int x,int y,int z){ade(x,y,z); ade(y,x,0);} bool bfs() { while(q.size())q.pop(); memset(dis,0,sizeof dis); dis[0]=1; q.push(0); while(q.size()) { int x=q.front(); q.pop(); for(int i=hd[x],u;i;i=nxt[i]) if(!dis[u=to[i]]&&c[i])dis[u]=dis[x]+1,q.push(u); } return dis[T]; } int dfs(int x,int fl) { if(x==T)return fl; int ret=0; for(int &i=cur[x],u;i;i=nxt[i]) { if(dis[u=to[i]]!=dis[x]+1||!c[i])continue; int tmp=dfs(u,min(fl-ret,c[i])); if(!tmp)dis[u]=0; c[i]-=tmp; c[i^1]+=tmp; ret+=tmp; if(ret==fl)break; } return ret; } int main() { n=rd(); S=0; T=n*n+n+1; int ans=0; for(int i=1,cnt=0;i<=n;i++) for(int j=1,x;j<=n;j++) { x=rd(); cnt++; ans+=x; add(S,cnt,x); add(cnt,n*n+i,inf); add(cnt,n*n+j,inf); } for(int i=1,x;i<=n;i++)x=rd(),add(n*n+i,T,x); while(bfs()) { memcpy(cur,hd,sizeof hd); ans-=dfs(S,inf); } printf("%d ",ans); return 0; }
以上是关于bzoj 3996 线性代数 —— 最大权闭合子图的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 4873 [Shoi2017]寿司餐厅 | 网络流 最大权闭合子图
BZOJ 1565 植物大战僵尸(拓扑排序+最大权闭合子图)