题目描述
为了提高智商,ZJY开始学习线性代数。她的小伙伴菠萝给她出了这样一个问题:给定一个n×nn×nn×n的矩阵BBB和一个1×n1×n1×n的矩阵CCC。求出一个1×n1×n1×n的01矩阵AAA。使得D=(A×B−C)×ATD=(A×B-C)×A^{\sf T}D=(A×B−C)×AT最大,其中ATA^{\sf T}AT为AAA的转置。输出DDD。
输入输出格式
输入格式:
第一行输入一个整数n。接下来n行输入B矩阵,第i行第j个数代表B接下来一行输入n个整数,代表矩阵C。矩阵B和矩阵C中每个数字都是不过1000的非负整数
输出格式:
输出一个整数,表示最大的D。
输入输出样例
输入样例#1:
3
1 2 1
3 1 0
1 2 3
2 3 7
输出样例#1:
2
说明
数据范围
对于 30% 的数据,1 ≤ n ≤ 15
对于 100% 的数据,1 ≤ n ≤ 500
分析:
化一下式子得到,
∑i=1n∑j=1nai∗aj∗bi,j−∑i=1nai∗ci\sum_{i=1}^{n}\sum_{j=1}^{n}a_i*a_j*b_{i,j}-\sum_{i=1}^{n}a_i*c_ii=1∑nj=1∑nai∗aj∗bi,j−i=1∑nai∗ci
也就是aia_iai选111有−ci-c_i−ci的价值,而同时选了aia_iai和aja_jaj就有bi,i+bi,j+bj,i+bj,jb_{i,i}+b_{i,j}+b_{j,i}+b_{j,j}bi,i+bi,j+bj,i+bj,j的价值。
显然可以最小割解决。
代码:
// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
const int maxn=517;
const int inf=0x3f3f3f3f;
using namespace std;
int n,s,t,ans,cnt;
int b[maxn][maxn],c[maxn],dis[maxn],ls[maxn];
struct edge{
int y,w,op,next;
}g[maxn*maxn*2];
queue <int> q;
void add(int x,int y,int w)
{
g[++cnt]=(edge){y,w,cnt+1,ls[x]};
ls[x]=cnt;
g[++cnt]=(edge){x,0,cnt-1,ls[y]};
ls[y]=cnt;
}
bool bfs()
{
while (!q.empty()) q.pop();
for (int i=s;i<=t;i++) dis[i]=inf;
dis[s]=0;
q.push(s);
while (!q.empty())
{
int x=q.front();
q.pop();
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
if ((g[i].w) && (dis[y]>dis[x]+1))
{
dis[y]=dis[x]+1;
if (y==t) return 1;
q.push(y);
}
}
}
return 0;
}
int dfs(int x,int maxf)
{
if (x==t) return maxf;
int ret=0;
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
if ((g[i].w) && (dis[y]==dis[x]+1))
{
int f=dfs(y,min(maxf-ret,g[i].w));
if (!f) dis[y]=-1;
g[i].w-=f;
g[g[i].op].w+=f;
ret+=f;
if (ret==maxf) break;
}
}
return ret;
}
int dinic()
{
int flow=0;
while (bfs()) flow+=dfs(s,inf);
return flow;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++) scanf("%d",&b[i][j]);
}
for (int i=1;i<=n;i++) scanf("%d",&c[i]);
s=0,t=n+1;
for (int i=1;i<=n;i++)
{
int sum=0;
for (int j=1;j<=n;j++)
{
sum+=b[i][j];
sum+=b[j][i];
ans+=b[i][j];
}
add(s,i,sum);
add(i,t,2*c[i]);
}
for (int i=1;i<=n;i++)
{
for (int j=i+1;j<=n;j++) add(i,j,b[i][j]+b[j][i]),add(j,i,b[i][j]+b[j][i]);
}
ans-=dinic()/2;
printf("%d",ans);
}