您的位置:首页 > 其它

【bzoj3996】【TJOI2015】【线性代数】【最小割】

2016-03-31 18:32 447 查看
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

题解:

化一下式子可以发现

ans=∑i=1n∑j=1nA[i]∗A[j]∗B[i][j]−∑i=1nA[i]∗C[i]

我们只要让上面那个式子值最小即可。

考虑网络流。

源点向A[i]连容量为C[i]的边。

A[i]和A[j]向B[i][j]连容量为inf的边。

B[i][j]向汇点连容量为B[i][j]的边。

设最小割为t.

则ans=∑B−t

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define inf 2100000000
#define N 300000
#define M 1000000
using namespace std;
int point
,next[M<<1],n,b[510][510],x,sum,t;
int cur
,gap
,pre
,dis
,T,cnt(1);
struct use{
int st,en,v;
}e[M<<1];
bool f;
void add(int x,int y,int v){
//cout<<x<<' '<<y<<' '<<v<<endl;
next[++cnt]=point[x];point[x]=cnt;e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;
next[++cnt]=point[y];point[y]=cnt;e[cnt].st=y;e[cnt].en=x;e[cnt].v=0;
}
int isap(int ss,int tt){
int mn,u(ss),i,ans(0);gap[0]=T;
for (int i=1;i<=T;i++) cur[i]=point[i];
while (dis[ss]<=T){
f=false;
for (i=cur[u];i;i=next[i])
if (e[i].v&&dis[e[i].en]+1==dis[u]){f=true;cur[u]=i;break;}
if (f){
pre[u=e[i].en]=i;
if (u==tt){
mn=inf;
for (i=tt;i!=ss;i=e[pre[i]].st) mn=min(mn,e[pre[i]].v);
ans+=mn;
for (i=tt;i!=ss;i=e[pre[i]].st) e[pre[i]].v-=mn,e[pre[i]^1].v+=mn;
u=ss;
}
}
else{
gap[dis[u]]--;if (!gap[dis[u]]) return ans;
for (mn=T,i=point[u];i;i=next[i])
if (e[i].v) mn=min(mn,dis[e[i].en]);
gap[dis[u]=mn+1]++;cur[u]=point[u];
if (u!=ss) u=e[pre[u]].st;
}
}
return ans;
}
int main(){
scanf("%d",&n);T=1+n*n+n;t=n+1;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%d",&b[i][j]),sum+=b[i][j];
for (int i=1;i<=n;i++){
scanf("%d",&x);
add(1,i+1,x);
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++){
++t;
add(i+1,t,inf);
add(j+1,t,inf);
add(t,T,b[i][j]);
}
cout<<sum-isap(1,T);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: