【TJOI2015】线性代数【最大流最小割+推导过程】

题目链接 线性代数 LibreOJ - 2100


首先,A矩阵*B矩阵 - C矩阵,我们会得到一个1*N的行列式,每一项是:\large (\sum_{i=1}^{N} a_i * b_{ij}) - c_j

然后再乘以A的转置行列式,

最后我们可以得到的是,我们所求的就是\large \sum_{j=1}^{N} (a_j * (\sum_{i=1}^{N} a_i * b_{ij}) - c_j)

于是,又知道\large a_i非0即1,所以就是取或者不取的问题了,又有i、j同时取这个问题,我们必须要解决,于是这里可以利用\large \sum_{j=1}^{N} (a_j * (\sum_{i=1}^{N} a_i * b_{ij}) - c_j)的性质来解决了。

我们想要这个式子的答案最大,于是,可以利用最小割(最大流)来求解。

对于\large b_{ij}我们可以给它开成N*N个点。对于\large c_j我们也是开成N个点,然后就是一个最大流,去知晓哪些点是被我们利用过了的。然后根据上面的公式求解答案。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 2.6e5 + 7, maxM = 1.1e6 + 7;
int N, head[maxN], cnt;
ll b[505][505], c[maxN], sum;
struct Eddge
{
    int nex, to; ll flow;
    Eddge(int a=-1, int b=0, ll c=0):nex(a), to(b), flow(c) {}
}edge[maxM];
inline void addEddge(int u, int v, ll w)
{
    edge[cnt] = Eddge(head[u], v, w);
    head[u] = cnt++;
}
inline void _add(int u, int v, ll w) { addEddge(u, v, w); addEddge(v, u, 0); }
struct Max_Flow
{
    int gap[maxN], cur[maxN], d[maxN], que[maxN], ql, qr, S, T, node;
    inline void init()
    {
        for(int i=0; i<=node + 1; i++)
        {
            gap[i] = d[i] = 0;
            cur[i] = head[i];
        }
        ++gap[d[T] = 1];
        que[ql = qr = 1] = T;
        while(ql <= qr)
        {
            int x = que[ql ++];
            for(int i=head[x], v; ~i; i=edge[i].nex)
            {
                v = edge[i].to;
                if(!d[v]) { ++gap[d[v] = d[x] + 1]; que[++qr] = v; }
            }
        }
    }
    inline ll aug(int x, ll FLOW)
    {
        if(x == T) return FLOW;
        int flow = 0;
        for(int &i=cur[x], v; ~i; i=edge[i].nex)
        {
            v = edge[i].to;
            if(d[x] == d[v] + 1)
            {
                ll tmp = aug(v, min(FLOW, edge[i].flow));
                flow += tmp; FLOW -= tmp; edge[i].flow -= tmp; edge[i ^ 1].flow += tmp;
                if(!FLOW) return flow;
            }
        }
        if(!(--gap[d[x]])) d[S] = node + 1;
        ++gap[++d[x]]; cur[x] = head[x];
        return flow;
    }
    inline ll max_flow()
    {
        init();
        ll ret = aug(S, INF);
        while(d[S] <= node) ret += aug(S, INF);
        return ret;
    }
} mf;
vector<int> vt;
ll tmp_Flow;
inline void init()
{
    cnt = 0; mf.node = N + N * N + 2; mf.S = 0; mf.T = N + N * N + 1; sum = 0;
    for(int i=0; i<=mf.node; i++) head[i] = -1;
}
inline int get_id(int i, int j) { return N * i + j; }
int main()
{
    scanf("%d", &N); init();
    for(int i=1; i<=N; i++) for(int j=1; j<=N; j++) scanf("%lld", &b[i][j]);
    for(int i=1; i<=N; i++) scanf("%lld", &c[i]);
    for(int i=1; i<=N; i++) _add(mf.S, i, c[i]);
    for(int i=1; i<=N; i++) for(int j=1; j<=N; j++) _add(j, get_id(i, j), INF);
    for(int i=1; i<=N; i++) for(int j=1; j<=N; j++) _add(get_id(i, j), mf.T, b[i][j]);
    tmp_Flow = mf.max_flow();
    for(int i=0; i<N; i++) if(!edge[i << 1].flow) vt.push_back(i + 1);
    int len = (int)vt.size();
    for(int j=0, u, v; j<len; j++)
    {
        u = vt[j];
        sum -= c[u];
        for(int i=0; i<len; i++)
        {
            v = vt[i];
            sum += b[u][v];
        }
    }
    printf("%lld\n", sum);
    return 0;
}
发布了818 篇原创文章 · 获赞 978 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/104507563