• BZOJ3996 [TJOI2015]线性代数


    Description

    给定(n*n)的矩阵(B)(1*n)的矩阵(C)。求一个(1*N)的01矩阵(A)使得((AB-C)A^T)最大。(A^T)(A)的转置。(nleq500),所有输入为不超过(1000)的非负整数。

    Solution

    [egin{aligned} (AB)_i&=sum_{j=1}^n A_jB_{j,i}\ (AB-C)_i&=left(sum_{j=1}^n A_jB_{j,i} ight) - C_i\ (AB-C)A^T&=sum_{i=1}^n A_ileft(sum_{j=1}^nA_jB_{j,i} ight)-A_iC_i\ &=sum_{i,j=1dots n} A_iA_jB_{i,j} -sum_{i=1}^nA_iC_i end{aligned} ]

    观察最后一个式子,可以看成:

    (n)个物品,第(i,j)两个物品同时选会获得(B_{i,j})的收益;选第(i)个物品会付出(C_i)的代价;求最大净收益。

    最小割即可。

    Code

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    const int N = 500;
    const int NN = 500000;
    const int M = 3000050;
    int pre[NN], nxt[M], to[M], ret[M], cnt;
    int dis[NN], que[NN];
    bool BFS(int S, int T) {
      int hd = 0, tl = 0;
      memset(dis, -1, sizeof dis);
      for (dis[que[tl++] = S] = 0; hd < tl; ++hd)
        for (int i = pre[que[hd]]; ~i; i = nxt[i])
          if (ret[i] && !~dis[to[i]]) dis[que[tl++] = to[i]] = dis[que[hd]] + 1;
      return dis[T] != -1;
    }
    int DFS(int x, int T, int maxf) {
      if (!maxf) return 0;
      if (x == T) return maxf;
      int ans = 0;
      for (int i = pre[x]; ~i; i = nxt[i])
        if (ret[i] && dis[to[i]] == dis[x] + 1) {
          int t = DFS(to[i], T, std::min(maxf - ans, ret[i]));
          ret[i] -= t; ret[i ^ 1] += t;
          ans += t;
        }
      if (ans < maxf) dis[x] = -1;
      return ans;
    }
    int solve(int S, int T) {
      int ans = 0;
      while (BFS(S, T)) ans += DFS(S, T, 1000000000);
      return ans;
    }
    inline void addEdge(int x, int y, int c) {
      nxt[cnt] = pre[x];
      ret[cnt] = c;
      to[pre[x] = cnt++] = y;
      nxt[cnt] = pre[y];
      ret[cnt] = 0;
      to[pre[y] = cnt++] = x;
    }
    int main() {
      int n;
      scanf("%d", &n);
      memset(pre, -1, sizeof pre);
      int S = n * (n + 1), T = S + 1;
      int ans = 0;
      for (int i = 0; i < n; ++i)
        for (int j = 0, v; j < n; ++j) {
          scanf("%d", &v);
          ans += v;
          int t = (i + 1) * n + j;
          addEdge(t, T, v);
          addEdge(i, t, 1000000000);
          addEdge(j, t, 1000000000);
        }
      for (int i = 0, v; i < n; ++i) {
        scanf("%d", &v);
        addEdge(S, i, v);
      }
      printf("%d
    ", ans - solve(S, T));
      return 0;
    }
    
  • 相关阅读:
    JS日期比较,使用正则表达式转换
    Using SQL*Loader to create an external table
    USACO试题beads的两种解法
    activiti5学习资料(5.12版本流程图的生成)
    黑马程序员_day20_Map集合
    开发者使用JasperReport——不同数据源之Map数据源
    给自己科谱:控制字符
    507 Jill Rides Again
    探讨工作流能给公司带来的几点益处
    ubuntu linux安装双系统的方法Win7、XP下均可
  • 原文地址:https://www.cnblogs.com/y-clever/p/8512395.html
Copyright © 2020-2023  润新知