BZOJ_3996_[TJOI2015]线性代数_最大权闭合子图
BZOJ_3996_[TJOI2015]线性代数_最大权闭合子图
Description
给出一个N*N的矩阵B和一个1*N的矩阵C。求出一个1*N的01矩阵A.使得
D=(A*B-C)*A^T最大。其中A^T为A的转置。输出D
Input
第一行输入一个整数N,接下来N行输入B矩阵,第i行第J个数字代表Bij.
接下来一行输入N个整数,代表矩阵C。矩阵B和矩阵C中每个数字都是不超过1000的非负整数。
Output
输出最大的D
Sample Input
3
1 2 1
3 1 0
1 2 3
2 3 7
1 2 1
3 1 0
1 2 3
2 3 7
Sample Output
2
HINT
1<=N<=500
根据乘法分配律可知,对于$b(i,j)$ ,只有$a[i],a[j]$ 都选才会有贡献。
而选择$a[j]$会导致选择$-c[j]$.
可以发现这是个最大权闭合子图的模型。
$S->b[i][j],b[i][j]->c[i],b[i][j]->c[j],c[i]->T$
代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 300050 #define M 2000050 #define inf 100000000 int head[N],to[M],nxt[M],flow[M],cnt=1,sum,n; int dep[N],Q[N],l,r,S,T,idx[510][510],c[510]; inline void add(int u,int v,int f) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f; to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0; } bool bfs() { memset(dep,0,sizeof(dep)); l=r=0;Q[r++]=S;dep[S]=1; while(l<r) { int x=Q[l++],i; for(i=head[x];i;i=nxt[i]) { if(!dep[to[i]]&&flow[i]) { dep[to[i]]=dep[x]+1; if(to[i]==T) return 1; Q[r++]=to[i]; } } } return 0; } int dfs(int x,int mf) { if(x==T) return mf; int i,nf=0; for(i=head[x];i;i=nxt[i]) { if(dep[to[i]]==dep[x]+1&&flow[i]) { int tmp=dfs(to[i],min(mf-nf,flow[i])); if(!tmp) dep[to[i]]=0; nf+=tmp; flow[i]-=tmp; flow[i^1]+=tmp; if(nf==mf) break; } } return nf; } void dinic() { int f; while(bfs()) while(f=dfs(S,inf)) sum-=f; printf("%d\n",sum); } int main() { int i,j,x; scanf("%d",&n); S=n*n+n+1;T=S+1; int tot=0; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { idx[i][j]=++tot; scanf("%d",&x); sum+=x; add(S,tot,x); } } for(i=1;i<=n;i++) { scanf("%d",&c[i]); add(i+n*n,T,c[i]); } for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { add(idx[i][j],n*n+i,inf); add(idx[i][j],n*n+j,inf); } } dinic(); }