题解:[TJOI2015]线性代数

传送门

为了提高智商,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。

其实这个题目本身不算难,只要把它给展开,然后就会发现整个式子变成了
a n s = i = 1 n j = 1 n a i a j b i j i = 1 n a i c i ans =\sum_{i=1}^{n}\sum_{j=1}^{n} ai*aj*bij-\sum_{i=1}^{n}ai*ci
(推理过程表示懒得打了QAQ)
然后看着这个式子我们可以这么理解,同时选 ai 和 aj 可以获得 bij 的收益,而选 ai 会有 ci 的损失,那么这就是很明显的网络流问题了

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define re register
#define gc getchar()
inline int read() {
    re int x=0,f=1;
    re char ch=gc;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f=-1;
        ch=gc;
    }
    while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=gc;
    return x*f;
}
const int N=4001000,INF=(1<<29);
struct node {
    int next,to,w;
} e[N<<4];
int h[N],n,cnt=1,s,t,m;
inline void add(int u,int v,int w) {
    e[++cnt]=(node) {h[u],v,w},h[u]=cnt;
    e[++cnt]=(node) {h[v],u,0},h[v]=cnt;
}
#define QXX(u) for(int i=h[u],v;v=e[i].to,i;i=e[i].next)
int deep[N];
inline int bfs() {
    queue<int> q;
    q.push(s);
    for (int i=1; i<=t; ++i) deep[i] = 0;
    deep[s]=1;
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        QXX(u) if(e[i].w&&!deep[v]) {
            deep[v]=deep[u]+1;
            q.push(v);
            if(v==t) return 1;
        }
    }
    return 0;
}
int dfs(int u,int flow) {
    if(u==t) return flow;
    int res=flow;
    QXX(u) if(e[i].w&&deep[v]==deep[u]+1) {
        int k=dfs(v,min(res,e[i].w));
        e[i].w-=k;
        e[i^1].w+=k;
        res-=k;
    }
    if(res==flow)
        deep[u]=0;
    return flow-res;
}

int id(int i,int j) {
    return (i-1)*n+1;
}
int ans,maxf=0;
int b[505],c[505][505];
int main() {

//	freopen("x.txt","r",stdin);

    n = read();
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            c[i][j] = read();
        }
    }
    for(int i = 1; i <= n; i++) b[i] = read();

    s=0, t=n*(n+1)+1;
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {
            add(s,i*n+j, c[i][j]);
            add(i*n+j,i,INF);
            add(i*n+j,j,INF);
            maxf+=c[i][j];
        }
    }
    for(int i=1; i<=n; i++) 
        add(i, t, b[i]);

    while(bfs()) {
        while((ans=dfs(s,INF))) maxf-=ans;
    }
    cout<<maxf<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43464026/article/details/87817530