1. 程式人生 > >[TJOI2015]線性代數

[TJOI2015]線性代數

pan getchar space https desc add head solution 個數字

題目鏈接

戳我

\(Describe\)

題目描述

為了提高智商,\(ZJY\)開始學習線性代數。她的小夥伴菠蘿給她出了這樣一個問題:給定一個\(n×n\)的矩陣\(B\)和一個\(1×n\)的矩陣\(C\)。求出一個\(1×n\)\(01\)矩陣\(A\)。使得\(D=(A*B-C)*A^T\) 最大,其中\(A^T\)\(A\)的轉置。輸出\(D\)

輸入格式:

第一行輸入一個整數\(n\)。接下來\(n\)行輸入\(B\)矩陣,第\(i\)行第\(j\)個數代表\(B\)接下來一行輸入\(n\)個整數,代表矩陣\(C\)。矩陣\(B\)和矩陣\(C\)中每個數字都是不過\(1000\)的非負整數

輸出格式:

輸出一個整數,表示最大的\(D\)

輸入樣例:
3
1 2 1
3 1 0
1 2 3
2 3 7

輸出樣例:
2

\(Solution\)

首先來化簡一下式子

\[D=(A*B-C)*A^T\]
\[=\sum_{i=1}^{n}(\sum_{j=1}^{n}A_j*B_{j,i}-C_i)*A_i\]
\[=\sum_{i=1}^{n}\sum_{j=1}^{n}A_i*A_j*B_{i,j}-\sum_{i=1}^{n}C_i*A_i\]

因為題目已經說明了\(A\)是一個\(01\)串,所以我們可以發現當\(A_i\)\(0\)的時候對答案並沒有任何貢獻,不用計算。當\(A_i\)

\(1\)時,會有\(C_i\)的花費。但如果同時選\(j\)會有\(B_{i,j}\)的花費.所以這顯然是一個最小割模型了。講1看為選,0為不選

建圖:

  • 將每個\(B_{ij}\)看做一個點,總共有\(n*n\)個點。將這\(S\)和這\(n*n\)個點相連,流量為\(B_{i,j}\)
  • 新建\(n\)個點。將這些點和\(T\)相連,流量為\(C_i\)
  • \(n*n\)個點和新建節點中的\(i,j\)相連,流量為\(inf\)

答案就是\(B\)矩陣內的和-最小割

\(Code\)

#include<bits/stdc++.h>
#define inf 1e9
using namespace std;
typedef long long ll;
int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
struct node{
    int to,next,v;
}a[2000001];
int head[1000001],cnt,n,m,s,t,x,y,z,dep[260000],sum,cur[260000];
void add(int x,int y,int c){
    a[++cnt].to=y,a[cnt].next=head[x],a[cnt].v=c,head[x]=cnt;
    a[++cnt].to=x,a[cnt].next=head[y],a[cnt].v=0,head[y]=cnt;
}
queue<int> q;
int bfs(){
    memset(dep,0,sizeof(dep));
    q.push(s);
    dep[s]=1;
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for(int i=head[now];i;i=a[i].next){
            int v=a[i].to;
            if(!dep[v]&&a[i].v>0)
                dep[v]=dep[now]+1,q.push(v);
        }
    }
    if(dep[t])
        return 1;
    return 0;
}
int dfs(int k,int list){
    if(k==t||!list)
        return list;
    for(int &i=cur[k];i;i=a[i].next){
        int v=a[i].to;
        if(dep[v]==dep[k]+1&&a[i].v>0){
            int p=dfs(v,min(list,a[i].v));
            if(p){
                a[i].v-=p;
                i&1?a[i+1].v+=p:a[i-1].v+=p;
                return p;
            }
        }
    }
    return 0;
}
int Dinic(){
    int ans=0,k;
    while(bfs()){
        for(int i=s;i<=t;i++)
            cur[i]=head[i];
        while((k=dfs(s,inf)))
            ans+=k;
    }
    return ans;
}
int main(){
    n=read(),s=0,t=n*n+n+1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            x=read(),sum+=x,add(s,(i-1)*n+j,x),add((i-1)*n+j,i+n*n,inf),add((i-1)*n+j,j+n*n,inf);
    for(int i=1;i<=n;i++)
        x=read(),add(i+n*n,t,x);
    printf("%d\n",sum-Dinic());
}

[TJOI2015]線性代數