首页 > 其他 > 详细

[TJOI2015]线性代数

时间:2019-04-18 10:03:01      阅读:103      评论:0      收藏:0      [点我收藏+]

题目

还是挺不错的题,首先你得看出来这是一个网络流

下面用\(A_{i},C_{i}\)来简记\(A_{1,i},C_{1,i}\)

首先是\(A\times B\),得到一个\(1\times n\),之后减掉矩阵\(C\),我们设得到的矩阵为\(D\)

满足\(D_j=\sum_{k=1}^nA_k\times B_{k,j}-C_j\)

之后是\(D\times A^T\)

结果是

\[\sum_{j=1}^nA_jD_j=\sum_{j=1}^n\sum_{k=1}^nA_jA_k\times B_{k,j}-\sum_{i=1}^nC_j\]

我们要最大化这个柿子,同时\(A\)又是一个\(0/1\)矩阵,我们可以想到最小割

如果\(B_{j,k}\)能产生贡献的话,那么就要求\(A_j=A_k=1\),但是\(A_j=A_k=1\)却需要减掉\(C_j,C_k\)

于是我们建立超级源汇,中间一排\(n\)个点,表示\(A\)

超级源连中间的每一个点\(i\)一条边权为\(C_i\)的边,表示割掉这条边去和超级汇相连,即\(A_i=1\),需要减掉\(C_i\)

对于一对点\((i,j)\),我们新建一个点\(g\)\(g\)向超级汇连边权为\(B_{i,j}\)的边,\(i,j\)\(g\)连边权\(inf\)的边,这样只有在\(i,j\)同时和超级汇相连的时候才不用割掉这条边

答案就是\(\sum_{i=1}^n\sum_{j=1}^nB_{i,j}-\text{最小割}\)

代码

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=505*505+505;
const int inf=99999999;
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
struct E{int v,nxt,f;}e[maxn*8];
int head[maxn],d[maxn],cur[maxn],c[505],b[505][505];
std::queue<int> q;
int n,num=1,S,T,ans;
inline void C(int x,int y,int f) {
    e[++num].v=y;e[num].nxt=head[x];
    e[num].f=f;head[x]=num;
}
inline void add(int x,int y,int f) {C(x,y,f),C(y,x,0);}
inline int BFS() {
    for(re int i=S;i<=T;i++) cur[i]=head[i],d[i]=0;
    d[S]=1;q.push(S);
    while(!q.empty()) {
        int k=q.front();q.pop();
        for(re int i=head[k];i;i=e[i].nxt)
        if(!d[e[i].v]&&e[i].f) d[e[i].v]=d[k]+1,q.push(e[i].v);
    }
    return d[T];
}
int dfs(int x,int now) {
    if(x==T||!now) return now;
    int flow=0,ff;
    for(re int& i=cur[x];i;i=e[i].nxt)
    if(d[e[i].v]==d[x]+1) {
        ff=dfs(e[i].v,min(now,e[i].f));
        if(ff<=0) continue;
        now-=ff,flow+=ff,e[i].f-=ff,e[i^1].f+=ff;
        if(!now) break;
    }
    return flow;
}
int main() {
    n=read();
    for(re int i=1;i<=n;i++)
        for(re int j=1;j<=n;j++) b[i][j]=read(),ans+=b[i][j];
    for(re int i=1;i<=n;i++) c[i]=read();
    T=n;for(re int i=1;i<=n;i++) add(S,i,c[i]);
    int ed=T+1;
    for(re int i=1;i<=n;i++) 
        for(re int j=1;j<=n;j++) ed++;
    for(re int i=1;i<=n;i++)
        for(re int j=1;j<=n;j++) {
            ++T;
            add(i,T,inf),add(j,T,inf);
            add(T,ed,b[i][j]);
        }
    ++T;
    while(BFS()) ans-=dfs(S,inf);
    printf("%d\n",ans);
    return 0;
}

[TJOI2015]线性代数

原文:https://www.cnblogs.com/asuldb/p/10727480.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!