bzoj 3996: [TJOI2015]线性代数

时间:2023-01-11 21:03:34

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

Sample Output

2

HINT

1<=N<=500

Source

经过推导得出:

bzoj 3996: [TJOI2015]线性代数

是一个最大权闭合子图的模型

选择一个Ai==1,会损失Ci;

对于一个点对(i,j),当Ai和Aj同时==1时,可以获得Bij的收益;

由于收益是同时依赖于两个点的,所以可以对每一个点对新建一个附加点tt,从s向其连Bij的边,然后tt向i,j连Inf;

其余的连边就是最大权闭合子图的套路了

最后正权和-最小割即为答案

(玄学剪枝真有用)

// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#define RG register
using namespace std;
typedef long long ll;
const int N=2000000;
const int Inf=19260817;
int gi()
{
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
int head[N],nxt[N],to[N],s[N],cnt=1,S,T,n,sum,q[N],level[N],vis[N],F,c[N];
int b[600][600],C[1000],tot;
inline void Addedge(int x,int y,int z) {
to[++cnt]=y,s[cnt]=z,nxt[cnt]=head[x],head[x]=cnt;
}
inline void lnk(int x,int y,int z){
Addedge(x,y,z);Addedge(y,x,0);
}
inline bool bfs(){
for(RG int i=S;i<=T;i++) level[i]=0,vis[i]=0;
int t=0,sum=1;
q[0]=S,level[S]=1,vis[S]=1;
while(t<sum){
int now=q[t++];
if(now==T) return 1;
for(RG int i=head[now];i;i=nxt[i]){
int y=to[i];
if(level[y]==0&&s[i]){
level[y]=level[now]+1;
q[sum++]=y;
}
}
}
return 0;
}
inline int dfs(int now,int maxf){
if(now==T) return maxf;
int ret=0;
for(RG int i=head[now];i;i=nxt[i]) {
int y=to[i],f=s[i];
if(level[y]==level[now]+1&&f) {
int minn=min(maxf-ret,f);
f=dfs(y,minn);
s[i]-=f;
s[i^1]+=f;ret+=f;
if(ret==maxf) break;
}
}
if(!ret) level[now]=0;
return ret;
}
inline void Dinic(){
while(bfs()) F+=dfs(S,Inf);
}
int main(){
n=gi();
for(RG int i=1;i<=n;i++)
for(RG int j=1;j<=n;j++) b[i][j]=gi();
for(RG int i=1;i<=n;i++) C[i]=gi(),tot+=C[i];
S=0,T=n+n*n+1;int ans=0,tt=n;
for(RG int i=1;i<=n;i++) lnk(i,T,C[i]);
for(RG int i=1;i<=n;i++){
for(RG int j=1;j<=n;j++){
tt++;lnk(S,tt,b[i][j]);ans+=b[i][j];
lnk(tt,i,Inf);lnk(tt,j,Inf);
}
}
Dinic();printf("%d\n",ans-F);
return 0;
}