Description
100%的数据中N≤600,B 矩阵元素的和<2^31 , C矩阵元素的和<2^31
Solution
- 拆一下矩乘可以发现一对二元关系,暴力连边就好了。对于一对i,j向一个新点连inf,新点向T连bi,j,S向i连ci,n2个点,n2条边。
- 其实是最大闭权和子图。S向i连bi,j,i向j连bi,j,i向T连ci,对于任意i,j分别考虑后就可以发现这是对的。对流量求和,最后S向i连,变成一个n个点,n2条边的网络流。
- 对于这一类比较密集的图,SAP是最好的选择。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 605
#define maxe 1000005
#define inf ((1ll<<31)-1)
#define I(x) ((x&1)?x+1:x-1)
using namespace std;
int n,i,j,k,sum,ans;
int B[maxn][maxn],C[maxn];
int S,T,tot;
int em,e[maxe],nx[maxe],ls[maxn],ec[maxe];
int dis[maxn],gap[maxn],cur[maxn];
void read(int &x){
x=0; char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
}
void insert(int x,int y,int z){
em++; e[em]=y; nx[em]=ls[x]; ls[x]=em; ec[em]=z;
em++; e[em]=x; nx[em]=ls[y]; ls[y]=em; ec[em]=0;
}
int SAP(int x,int flow){
if (x==T) return flow;
int use=0,i,tmp;
for (i=cur[x];i;i=nx[i]){
cur[x]=i;
if (ec[i] && dis[e[i]]+1==dis[x]){
tmp=SAP(e[i],min(flow-use,ec[i]));
use+=tmp,ec[i]-=tmp,ec[i^1]+=tmp;
if (flow==use) return use;
}
}
cur[x]=ls[x];
if (!(--gap[dis[x]])) dis[S]=T;
++gap[++dis[x]];
return use;
}
int main(){
read(n);
for(i=1;i<=n;i++) for(j=1;j<=n;j++) read(B[i][j]),ans+=B[i][j];
for(i=1;i<=n;i++) read(C[i]);
S=n+1,T=n+2,em=1;
for(i=1;i<=n;i++) {
int sum=0;
for(j=1;j<=n;j++) sum+=B[j][i];
insert(S,i,sum);
insert(i,T,C[i]);
}
for(i=1;i<=n;i++) for(j=1;j<=n;j++) if (i!=j) insert(i,j,B[j][i]);
while (dis[S]<T) ans-=SAP(S,inf);
printf("%d",ans);
}