洛谷P3973 - [TJOI2015]线性代数

Portal

Description

给定一个\(n\times n\)的矩阵\(B\)和一个\(1×n\)的矩阵\(C\)。求出一个\(1×n\)的01矩阵\(A\),使得\(D=(A×B-C)×A^T\)最大,其中\(A^T\)\(A\)的转置。输出\(D\)

Solution

先展开一波。
\[\begin{align*} D &= (A×B-C)×A^T \\ &= \begin{bmatrix} \sum_{i=1}^n a_ib_{i1}-c_1 & \sum_{i=1}^n a_ib_{i2}-c_2 & ... & \sum_{i=1}^n a_ib_{in}-c_n \end{bmatrix} \times A^T \\ &= \sum_{j=1}^n a_j (\sum_{i=1}^n a_ib_{ij}-c_j) \\ &= \sum_{i=1}^n \sum_{j=1}^n a_ia_jb_{ij} - \sum_{i=1}^n a_ic_i \end{align*}\] 观察发现,要想获得\(b_{ij}\)的价值就需要让\(a_i=a_j=1\),但如果\(a_i\)被选就得付出\(c_i\)的代价。那么同太空飞行计划,求最大权闭合图即可。

Code

//线性代数
#include <cstdio>
#include <cstring>
inline char gc()
{
    static char now[1<<16],*S,*T;
    if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;}
    return *S++;
}
inline int read()
{
    int x=0; char ch=gc();
    while(ch<'0'||'9'<ch) ch=gc();
    while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x;
}
int min(int x,int y) {return x<y?x:y;}
int const N=3e5;
int const INF=0x7FFFFFFF;
int n;
int cnt,h[N];
struct edge{int v,c,nxt;} ed[N*6];
void edAdd(int u,int v,int c)
{
    cnt++; ed[cnt].v=v,ed[cnt].c=c,ed[cnt].nxt=h[u],h[u]=cnt;
    cnt++; ed[cnt].v=u,ed[cnt].c=0,ed[cnt].nxt=h[v],h[v]=cnt;
}
int s,t;
int dpt[N]; int Q[N],op,cl;
bool bfs()
{
    memset(dpt,0,sizeof dpt);
    dpt[s]=1,Q[++cl]=s;
    while(op<cl)
    {
        int u=Q[++op]; if(u==t) break;
        for(int i=h[u];i;i=ed[i].nxt)
        {
            int v=ed[i].v;
            if(!dpt[v]&&ed[i].c) dpt[v]=dpt[u]+1,Q[++cl]=v;
        }
    }
    return dpt[t];
}
int fill(int u,int in)
{
    if(u==t) return in;
    int out=0;
    for(int i=h[u];i&&in>out;i=ed[i].nxt)
    {
        int v=ed[i].v,c=ed[i].c;
        if(!c||dpt[v]!=dpt[u]+1) continue;
        int fl=fill(v,min(in-out,c));
        if(!fl) dpt[v]=0;
        else out+=fl,ed[i].c-=fl,ed[i^1].c+=fl;
    }
    return out;
}
int maxFlow()
{
    int res=0;
    while(bfs()) res+=fill(s,INF);
    return res;
}
int main()
{
    n=read(); int ans=0;
    s=0,t=n*n+n+1; cnt=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            int u=(i-1)*n+j,c=read(); ans+=c;
            edAdd(s,u,c); edAdd(u,n*n+i,INF),edAdd(u,n*n+j,INF);
        }
    for(int i=1;i<=n;i++) edAdd(n*n+i,t,read());
    printf("%d\n",ans-maxFlow());
    return 0;
}

P.S.

洛谷A了,原数据A了,但BZOJ上RE?!

转载于:https://www.cnblogs.com/VisJiao/p/LgP3973.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值