jzoj1900. 矩阵

Description
在这里插入图片描述
Input
输入第1行有一个整数N。
第2~N+1行每行N个非负整数,用空格隔开,描述B 矩阵。
第N+2行,有N个非负整数,用空格隔开,描述C 矩阵。
输入数据保证没有多余的空格和换行。

Output
只需要输出一个整数,表示你找到的元素值最大 D矩阵。

Sample Input
3
1 2 1
3 1 0
1 2 3
2 3 7

Sample Output
2

Data Constraint

Hint
【样例说明】
矩阵 可能为:( 0 , 0 , 0 ) , ( 0 , 0 , 1 ) , ( 0 , 1 , 0 ) ,( 0 , 1 , 1 ) ,( 1 , 0 , 0 ) ,( 1 , 0 , 1 ) ,( 1 , 1 , 0 ) 或( 1 , 1 , 1 ) ,对应得到的 结果依次为:0 ,-4 ,-2 ,-4 ,-1 ,-3 ,2 和 2 。
其中当A=( 1 , 1 , 0 ) 或A=( 1 , 1 , 1 ) ,D=(2) ,此时 D矩阵的元素值最大。
【数据范围】
30%的数据中N≤20;
70%的数据中N≤200;
100%的数据中N≤600,B 矩阵元素的和<2^31 , C矩阵元素的和<2^31;

【友情提示(对于使用C/C++的同学)】
由于题目读入的数据规模较大,使用cin或者scanf读入可能会导致超时,所以推荐使用gets读入,这里友情提供一个gets读入的过程,可以直接使用:

void getline(int data[])
{
int i=0,k=0; char ch[20000];
gets(ch);
for (;ch[k]!=’\0’;k++)
{
data[i]=0;
for (;ch[k]!=’\0’ && ch[k]!=’ ';k++) data[i]=data[i]*10+ch[k]-‘0’;
i++;
};
}

假设a是你的程序定义的一个一维int数组,当调用getline(a)时,这个过程会读入下一行的所有数字。假设当前行有x个数字,那么这些数字会存放在a[0]~a[x-1]中(注意:需要保证a数组的大小足够)。

题解

读入优化良心,但我选择freadPascal选手因语言过激被踢出直播间
拆一下式子,可以发现
a n s = ∑ a i = 1 ∑ a j = 1 b [ i ] [ j ] − ∑ a i = 1 c [ i ] ans=\sum_{ai=1}{\sum_{aj=1}{b[i][j]}}-\sum_{ai=1}{c[i]} ans=ai=1aj=1b[i][j]ai=1c[i]

考虑网络流
先把所有b加在一起,若ai=0则减去b中以(i,i)为中心的一个十字,否则减去c
用这些东西来建图跑最小割,那么最小割就是减去的总和
在这里插入图片描述
(中间i–>j连bi,j,j–>i连bj,i)
可以发现,若最小割割去了ci,则代表ai=1,否则割了∑bi,k就代表ai=0
原因见上文
但是由于ai=0时删去的是一个十字,且删的数不能重复,所以比较特殊

根据不同的最小割来体会上图的正确性
①割了i–>T和j–>T
表示ai=aj=1,减去的是ci+cj
②割了S–>i和S–>j
表示ai=aj=0,因为删的点不能重复,所以尽管删掉的是一个十字,但现在考虑的是第i行和第j行的代价(多行也一样),所以就是∑bi,k+∑bj,l
③割了S–>i和j–>i和j–>T(或者反过来)
表示ai=0,aj=1,要减去第j行被i删去的点,即bj,i

妙啊

code

把i–>j和j–>i合在一起(不连反向边)会快一些

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define inf 2147483647
using namespace std;

int a[800001][3];
int ls[602];
int cur[602];
int b[601][601];
int c[601];
int f[602];
int g[602];
char st[5000001];
char *Ch=st;
int N,n,i,j,k,l,len,ans;

int Get()
{
    
    
	int x=0;
	
	while (*Ch<'0' || *Ch>'9') *++Ch;
	while (*Ch>='0' && *Ch<='9') x=x*10+(*Ch-'0'),*++Ch;
	
	return x;
}

void New(int x,int y,int z)
{
    
    
	++len;
	a[len][0]=y;
	a[len][1]=ls[x];
	ls[x]=len;
	a[len][2]=z;
}
void NEW(int x,int y,int z)
{
    
    
	New(x,y,z);
	New(y,x,0);
}

int dfs(int t,int flow)
{
    
    
	int i,use=0;
	
	if (t==N)
	return flow;
	
	for (i=cur[t]; i; i=a[i][1])
	{
    
    
		cur[t]=i;
		
		if (a[i][2] && f[t]==f[a[i][0]]+1)
		{
    
    
			int w=dfs(a[i][0],min(flow-use,a[i][2]));
			
			use+=w;
			a[i][2]-=w;
			a[i^1][2]+=w;
			
			if (use==flow)
			return use;
		}
	}
	
	cur[t]=ls[t];
	
	--g[f[t]];
	if (!g[f[t]])
	{
    
    
		f[0]=N+2;
		return use;
	}
	++f[t];
	++g[f[t]];
	
	return use;
}

int main()
{
    
    
//	freopen("matrix0.in","r",stdin);
//	freopen("S8_13_1.in","r",stdin);
	
	fread(st,1,5000001,stdin);
	
	len=1;
	
	n=Get();
	N=n+1;
	fo(i,1,n)
	{
    
    
		l=0;
		
		fo(j,1,n)
		{
    
    
			b[i][j]=Get();
			
			l+=b[i][j];
			ans+=b[i][j];
		}
		
		NEW(0,i,l);
	}
	fo(i,1,n)
	{
    
    
		c[i]=Get();
		NEW(i,N,c[i]);
	}
	
	fo(i,1,n)
	{
    
    
		fo(j,i+1,n)
		{
    
    
			New(i,j,b[i][j]);
			New(j,i,b[j][i]);
		}
	}
	
	g[0]=N+1;
	while (f[0]<N+2)
	ans-=dfs(0,inf);
	
	printf("%d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/gmh77/article/details/99468872
今日推荐