P3973 [TJOI2015]线性代数
作者:互联网
题意描述:
给你一个 \(n\times n\) 的矩阵 \(B\) 和一个 \(1\times n\) 的矩阵 \(C\) , 让你求一个 \(1\times n\) 的 \(01\) 矩阵 \(A\), 使得: \(D = (A\times B - C)\times A^T\) 的值最大,输出这个最大值。
注: \(A^T\) 即 \(A\) 的转置,也就是将 \(A\) 的行和列交换后得到的矩阵。
数据范围: \(n\leq 500\) .
solution:
乍一看,可能一点思路都没有。
我们先把求和的式子展开:
\[(A\times B-C)\times A^T\\ = A\times B \times A^T - C\times A^T\\ = \displaystyle\sum_{i=1}^{n}\sum_{j=1}^{n} A_iA_jB_{ij} - \sum_{i=1}^{n} C_iA_i \]然后你会发现,当 \(A_i = 1\) 的代价为 \(C_i\) 当 \(A_i\) 和 \(A_j\) 同为 \(1\) 的时候收益为 \(B_{ij}\) .
这就是一个最大权闭合子图的模型。
建图:
- 对于每一个 \(b_{ij}\), 新建一个点 \(u\) ,表示这一组合。由 \(s\) 向 \(u\) 连一条容量为 \(b_{ij}\) 的边,由 \(u\) 分别向右侧的· \(i\) 和 \(j\) 两个点连一条容量为 \(inf\) 的边。
- 由右侧的点 \(i\) 向汇点连一条容量为 \(c_i\) 的边
最后 \(b_{ij}\) 之和减去最小割就是答案。
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int inf = 1e7+10;
const int N = 1e6+10;
int n,cnt,sum,ans,s,t,tot = 1;
int head[N],dep[N],c[N],b[1010][1010],id[1010][1010];
struct node
{
int to,net,w;
}e[N<<1];
inline int read()
{
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * w;
}
void add(int x,int y,int w)
{
e[++tot].to = y;
e[tot].w = w;
e[tot].net = head[x];
head[x] = tot;
}
bool bfs()
{
queue<int> q;
for(int i = 0; i <= t; i++) dep[i] = 0;
q.push(s); dep[s] = 1;
while(!q.empty())
{
int x = q.front(); q.pop();
for(int i = head[x]; i; i = e[i].net)
{
int to = e[i].to;
if(e[i].w && !dep[to])
{
dep[to] = dep[x] + 1;
q.push(to);
if(to == t) return 1;
}
}
}
return 0;
}
int dinic(int x,int flow)
{
if(x == t || !flow) return flow;
int rest = flow, val = 0;
for(int i = head[x]; i && rest; i = e[i].net)
{
int to = e[i].to;
if(!e[i].w || dep[to] != dep[x] + 1) continue;
val = dinic(to,min(rest,e[i].w));
if(val == 0) dep[to] = 0;
e[i].w -= val, e[i^1].w += val, rest -= val;
}
return flow - rest;
}
int main()
{
n = read();
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
b[i][j] = read();
id[i][j] = ++cnt;
}
}
for(int i = 1; i <= n; i++) c[i] = read();
s = 0, t = cnt + n + 1;
for(int i = 1; i <= n; i++)//建图
{
for(int j = 1; j <= n; j++)
{
sum += b[i][j];
add(s,id[i][j],b[i][j]), add(id[i][j],s,0);
add(id[i][j],cnt+i,inf), add(cnt+i,id[i][j],0);
add(id[i][j],cnt+j,inf), add(cnt+j,id[i][j],0);
}
}
for(int i = 1; i <= n; i++) add(cnt+i,t,c[i]), add(t,cnt+i,0);
int flow = 0;
while(bfs())
{
while(flow = dinic(s,inf)) ans += flow;
}
printf("%d\n",sum-ans);
return 0;
}
标签:P3973,int,sum,times,ij,TJOI2015,线性代数,include,1010 来源: https://www.cnblogs.com/genshy/p/14409497.html