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=1∑aj=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);
}