T1 P3973 [TJOI2015]线性代数
思路:
矩阵 A 为一个 n*m 的矩阵
矩阵 A 的转置
A
T
A^T
AT 即为一个 m*n 的矩阵,其中
A
i
,
j
T
=
A
j
,
i
A^T_{i,j}=A_{j,i}
Ai,jT=Aj,i
有
(
A
∗
B
−
C
)
∗
A
T
A
∗
B
∗
A
T
−
C
∗
A
T
(A*B-C)*A^T\\ A*B*A^T-C*A^T
(A∗B−C)∗ATA∗B∗AT−C∗AT
对于 B 中的一个数
B
i
,
j
B_{i,j}
Bi,j,它的贡献为
B
i
,
j
∗
A
i
∗
A
j
B_{i,j}*A_{i}*A_{j}
Bi,j∗Ai∗Aj,当
A
i
A_{i}
Ai 与
A
j
A_{j}
Aj 都为 1 时,
B
i
,
j
B_{i,j}
Bi,j 有贡献
对于 C 中的一个数
C
i
,
j
C_{i,j}
Ci,j,它的贡献为
C
i
∗
A
i
C_{i}*A_{i}
Ci∗Ai,当
A
i
A_{i}
Ai 为 1 时,
C
i
C_{i}
Ci 有贡献
于是考虑最小割
先全选
B
i
,
j
B_{i,j}
Bi,j,然后割去最少的
B
i
,
j
B_{i,j}
Bi,j 与
C
i
C_{i}
Ci
两点间连 INF 边表示两点不可分割
于是源点向
B
i
,
j
B_{i,j}
Bi,j 连边,流量为
B
i
,
j
B_{i,j}
Bi,j
B
i
,
j
B_{i,j}
Bi,j 向
C
i
C_{i}
Ci 和
C
j
C_{j}
Cj 连边,流量为 INF
C
i
C_{i}
Ci 向汇点连边,流量为
C
j
C_{j}
Cj
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define S 0
#define T n*(n+1)+1
inline int in{
int s=0,f=1;char x;
for(x=getchar();x<'0'||x>'9';x=getchar()) if(x=='-') f=-1;
for( ;x>='0'&&x<='9';x=getchar()) s=(s*10)+(x&15);
return f==1?s:-s;
}
const int A=1e3+5;
const int B=2e6+5;
const int INF=(1<<30);
int n;
int a[A][A],b[A];
int head[B],tot_road=1;
struct Road{
int nex,to,w;
}road[2*B];
inline void ljb(int x,int y,int w){
road[++tot_road]={head[x],y,w};head[x]=tot_road;
}
inline int d1(int x,int y){
return (x-1)*n+y;
}
inline int d2(int x){
return n*n+x;
}
inline void scan(){
n=in;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=in;
for(int i=1;i<=n;i++) b[i]=in;
return;
}
inline void build(){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
ljb(S,d1(i,j),a[i][j]),ljb(d1(i,j),S,0);
if(i==j){
ljb(d1(i,j),d2(i),INF),ljb(d2(i),d1(i,j),0);
}
else{
ljb(d1(i,j),d2(i),INF),ljb(d2(i),d1(i,j),0);
ljb(d1(i,j),d2(j),INF),ljb(d2(j),d1(i,j),0);
}
}
for(int i=1;i<=n;i++)
ljb(d2(i),T,b[i]),ljb(T,d2(i),0);
return;
}
int maxflow=0;
int dep[B],sum[B];
inline void BFS(){
memset(dep,-1,sizeof(dep));
memset(sum,0,sizeof(sum));
queue <int> q;
dep[T]=0,sum[dep[T]]++;
q.push(T);
while(!q.empty()){
int x=q.front();q.pop();
for(int y=head[x];y;y=road[y].nex){
int z=road[y].to;
if(dep[z]!=-1) continue;
dep[z]=dep[x]+1,sum[dep[z]]++;
q.push(z);
}
}
return;
}
inline int DFS(int x,int flow){
if(x==T){
maxflow+=flow;
return flow;
}
int used=0;
for(int y=head[x];y;y=road[y].nex){
int z=road[y].to,w=road[y].w;
if(w&&dep[z]==dep[x]-1){
int after=DFS(z,min(w,flow-used));
if(after){
used+=after;
road[y].w-=after;
road[y^1].w+=after;
}
}
if(used==flow) return used;
}
if(!--sum[dep[x]]) dep[T]=T+1;
sum[++dep[x]]++;
return used;
}
inline void ISAP(){
maxflow=0;
BFS();
while(dep[T]<=T) DFS(S,INF);
return;
}
inline void print(){
int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
ans+=a[i][j];
printf("%d\n",ans-maxflow);
return;
}
signed main(){
scan();
build();
ISAP();
print();
return 0;
}