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
分析
倒腾下式子发现是经典最小割建模
然后,就没有然后了
代码
#include <bits/stdc++.h>
#define N 300005
#define ll long long
#define INF 0x7fffff
struct NOTE
{
int to,next,c;
}e[N*20];
int last[N];
int cnt;
void add(int x,int y,int c)
{
e[++cnt] = (NOTE) {y,last[x],c}; last[x] = cnt;
e[++cnt] = (NOTE) {x,last[y],0}; last[y] = cnt;
}
int dis[N];
int cur[N];
int ans;
int s,t;
bool bfs()
{
for (int i = s; i <= t; i++)
dis[i] = 0;
dis[s] = 1;
std::queue<int> Q;
Q.push(s);
while (!Q.empty())
{
int u = Q.front();
Q.pop();
for (int i = last[u]; i; i = e[i].next)
if (e[i].c && !dis[e[i].to])
{
dis[e[i].to] = dis[u] + 1;
if (e[i].to == t)
return 1;
Q.push(e[i].to);
}
}
return 0;
}
int dfs(int x,int maxf)
{
if (x == t || !maxf)
return maxf;
int ret = 0;
for (int &i = cur[x]; i; i = e[i].next)
if (e[i].c && dis[e[i].to] == dis[x] + 1)
{
int f = dfs(e[i].to,std::min(e[i].c,maxf - ret));
ret += f;
e[i].c -= f;
e[i^1].c += f;
if (ret == maxf)
break;
}
return ret;
}
void dinic()
{
while (bfs())
{
for (int i = s; i <= t; i++)
cur[i] = last[i];
ans += dfs(s,INF);
}
}
int n;
int main()
{
scanf("%d",&n);
t = n + n * n + 1;
int id = n;
int tot = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
int x;
scanf("%d",&x);
id++;
tot += x;
add(i,id,INF);
add(j,id,INF);
add(id,t,x);
}
for (int i = 1; i <= n; i++)
{
int x;
scanf("%d",&x);
add(s,i,x);
}
dinic();
std::cout<<tot - ans<<std::endl;
}