【BZOJ3996】[TJOI2015]线性代数 最大权闭合图

【BZOJ3996】[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

Sample Output

2

HINT

 1<=N<=500

题解:上面的那个式子我们用乘法分配律拆开,然后直观理解就是如果想要获得B中(i,j)的权值,A[i]和A[j]都必须是1,如果A[i]是1,那么就一定要付出C[i]的代价,这就变成了一个求最大权闭合图的问题,建图还是挺容易的吧?

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
int to[3000010],next[3000010],val[3000010],d[300000],head[300000];
queue<int> q;
int n,cnt,tot,m,ans,S,T;
int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
int bfs()
{
	int i,u;
	memset(d,0,sizeof(d));
	while(!q.empty())	q.pop();
	q.push(S),d[S]=1;
	while(!q.empty())
	{
		u=q.front(),q.pop();
		for(i=head[u];i!=-1;i=next[i])
		{
			if(!d[to[i]]&&val[i])
			{
				d[to[i]]=d[u]+1;
				if(to[i]==T)	return 1;
				q.push(to[i]);
			}
		}
	}
	return 0;
}
int dfs(int x,int mf)
{
	if(x==T)	return mf;
	int i,temp=mf,k;
	for(i=head[x];i!=-1;i=next[i])
	{
		if(d[to[i]]==d[x]+1&&val[i])
		{
			k=dfs(to[i],min(temp,val[i]));
			if(!k)	d[to[i]]=0;
			val[i]-=k,val[i^1]+=k,temp-=k;
			if(!temp)	break;
		}
	}
	return mf-temp;
}
void add(int a,int b,int c)
{
	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
	to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++;
}
int main()
{
	m=n=rd(),tot=0,S=0,T=n*n+n+1;
	int i,j,a;
	memset(head,-1,sizeof(head));
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
			a=rd(),tot+=a,add(S,++m,a),add(m,i,1<<30),add(m,j,1<<30);
	for(i=1;i<=n;i++)	add(i,T,rd());
	while(bfs())	ans+=dfs(S,1<<30);
	printf("%d",tot-ans);
	return 0;
}
posted @ 2017-05-18 07:12  CQzhangyu  阅读(245)  评论(0编辑  收藏  举报