HYSBZ 3996 线性代数

探讨如何通过网络流算法解决一个特定的线性代数问题:寻找01矩阵A,使(A×B-C)×A^T最大化。解析模型转化思路与实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HYSBZ 3996 线性代数

题目描述:

输入一个 N×N 的矩阵 B 和一个 1×N 的列向量 C ,求一个 01 矩阵 A ,使得 (A×BC)×AT 最大(可以证明这是一个 1×1 的矩阵)。输出那个最大的值。

题解:

(A×BC)×AT=A×B×ATC×AT=ijA1,jA1,iBj,iiA1,iC1,i

模型转化,假设有 N 个物品, A1,i 表示第 i 个选不选,选的话去要付出 C1,i 的代价,但如果两个物品 i j 都选就会得到 Bi,j 的收益,问最大收益和是多少。

于是就变成了网络流经典问题。算了一下大概有 3105 个点, 2106 条边,我也不知道为什么能跑的过去……

题目链接: vjudge 原网站

代码:


#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXM = 300007;
const int MAXG = 2000007;

#define encode(i, j) (N * (i) + (j))

#define S (0)
#define T (N * N + N + 1)

const int INF = 0x3f3f3f3f;

static struct
{
    int v, w, next;
} edge[MAXG];
static int N, G, sum, head[MAXM], dist[MAXM];

inline void add_edge(int u, int v, int w)
{
    edge[G].v = v; edge[G].w = w; edge[G].next = head[u]; head[u] = G++;
    edge[G].v = u; edge[G].w = 0; edge[G].next = head[v]; head[v] = G++;
}

inline bool bfs(void)
{
    queue<int> Q;
    memset(dist, 0, sizeof(dist));
    Q.push(S); dist[S] = 1;
    while (!Q.empty())
    {
        int x = Q.front(); Q.pop();
        for (int i = head[x]; ~i; i = edge[i].next)
            if (edge[i].w && !dist[edge[i].v])
                Q.push(edge[i].v), dist[edge[i].v] = dist[x] + 1;
    }
    return dist[T];
}

int dfs(int x, int f)
{
    if (x == T) return f;
    int r = 0;
    for (int i = head[x]; ~i && r < f; i = edge[i].next)
        if (edge[i].w && dist[edge[i].v] == dist[x] + 1)
        {
            int delta = dfs(edge[i].v, min(f - r, edge[i].w));
            r += delta;
            edge[i].w -= delta; edge[i^1].w += delta;
        }
    if (!r) dist[x] = -1;
    return r;
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d", &N);
    for (int i = 1; i <= N; i++)
        for (int j = 1, x; j <= N; j++)
        {
            scanf("%d", &x);
            sum += x;
            add_edge(S, encode(i, j), x);
            add_edge(encode(i, j), i, INF);
            add_edge(encode(i, j), j, INF);
        }
    for (int i = 1, x; i <= N; i++)
        scanf("%d", &x), add_edge(i, T, x);
    while (bfs())
        sum -= dfs(S, INF);
    printf("%d\n", sum);
    return 0;
}

提交记录(AC / Total = 1 / 2):

Run IDRemote Run IDTime(ms)Memory(kb)ResultSubmit Time
87381231991020819836RE2017-04-11 08:55:59
87381471991032158827556AC2017-04-11 09:02:30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值