JZOJ1900. 【2010集训队出题】矩阵

Description

在这里插入图片描述
100%的数据中N≤600,B 矩阵元素的和<2^31 , C矩阵元素的和<2^31

Solution

  • 拆一下矩乘可以发现一对二元关系,暴力连N2N^2边就好了。对于一对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连 bi,j\sum\ bi,j,变成一个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);
}
posted @ 2019-08-15 08:06  Deep_Thinking  阅读(104)  评论(0编辑  收藏  举报