题目描述

给出一个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个数字代表Bij.
接下来一行输入N个整数,代表矩阵C。矩阵B和矩阵C中每个数字都是不超过1000的非负整数。

输出

输出最大的D

样例输入

3
1 2 1
3 1 0
1 2 3
2 3 7

样例输出

2

提示

1<=N<=500

如果没有C矩阵,答案就是B矩阵中每个数的和假设为ans,那么有了C矩阵,我们就是想使ans减小的尽量少。

对于C中每个元素,要么就是ans直接减掉这个元素的值,也就是A中对应位置选1;要么就是不要B中的一些元素,也就是A中一些的位置选0来防止ans减掉这个C中元素的值。

那么这个问题就可转化成最小割,将S连向B中每个点,流量为对应B中的点权值;将B中每个点连向这个点对应的行和列代表的点,流量为INF;最后再将列代表的点连向汇点,流量为C中对应点的权值。

  1. #include<set>
  2. #include<map>
  3. #include<cmath>
  4. #include<queue>
  5. #include<stack>
  6. #include<vector>
  7. #include<cstdio>
  8. #include<bitset>
  9. #include<cstring>
  10. #include<iostream>
  11. #include<algorithm>
  12. #define INF 0x3f3f3f3f
  13. using namespace std;
  14. int next[5000001];
  15. int to[5000001];
  16. int val[5000001];
  17. int head[1000001];
  18. int tot=1;
  19. int q[1000001];
  20. int bak[1000001];
  21. int n,x;
  22. int S,T;
  23. int ans;
  24. int sum;
  25. int d[1000001];
  26. void add(int x,int y,int v)
  27. {
  28. tot++;
  29. next[tot]=bak[x];
  30. bak[x]=tot;
  31. to[tot]=y;
  32. val[tot]=v;
  33. tot++;
  34. next[tot]=bak[y];
  35. bak[y]=tot;
  36. to[tot]=x;
  37. val[tot]=0;
  38. }
  39. bool bfs(int S,int T)
  40. {
  41. int r=0;
  42. int l=0;
  43. memset(d,-1,sizeof(d));
  44. q[r++]=T;
  45. d[T]=2;
  46. while(l<r)
  47. {
  48. int now=q[l];
  49. for(int i=bak[now];i;i=next[i])
  50. {
  51. if(d[to[i]]==-1&&val[i^1]!=0)
  52. {
  53. d[to[i]]=d[now]+1;
  54. q[r++]=to[i];
  55. }
  56. }
  57. l++;
  58. }
  59. if(d[S]==-1)
  60. {
  61. return false;
  62. }
  63. else
  64. {
  65. return true;
  66. }
  67. }
  68. int dfs(int x,int flow)
  69. {
  70. if(x==T)
  71. {
  72. return flow;
  73. }
  74. int now_flow;
  75. int used=0;
  76. for(int &i=head[x];i;i=next[i])
  77. {
  78. if(d[to[i]]==d[x]-1&&val[i]!=0)
  79. {
  80. now_flow=dfs(to[i],min(flow-used,val[i]));
  81. val[i]-=now_flow;
  82. val[i^1]+=now_flow;
  83. used+=now_flow;
  84. if(now_flow==flow)
  85. {
  86. return flow;
  87. }
  88. }
  89. }
  90. if(used==0)
  91. {
  92. d[x]=-1;
  93. }
  94. return used;
  95. }
  96. void dinic()
  97. {
  98. while(bfs(S,T)==true)
  99. {
  100. memcpy(head,bak,sizeof(bak));
  101. ans+=dfs(S,INF);
  102. }
  103. }
  104. int main()
  105. {
  106. scanf("%d",&n);
  107. S=n*n+n+1;
  108. T=n*n+n+2;
  109. for(int i=1;i<=n;i++)
  110. {
  111. for(int j=1;j<=n;j++)
  112. {
  113. scanf("%d",&x);
  114. sum+=x;
  115. add(S,(i-1)*n+j,x);
  116. add((i-1)*n+j,n*n+i,INF);
  117. add((i-1)*n+j,n*n+j,INF);
  118. }
  119. }
  120. for(int i=1;i<=n;i++)
  121. {
  122. scanf("%d",&x);
  123. add(n*n+i,T,x);
  124. }
  125. dinic();
  126. printf("%d",sum-ans);
  127. }

BZOJ3996[TJOI2015]线性代数——最小割的更多相关文章

  1. 【BZOJ-3996】线性代数 最小割-最大流

    3996: [TJOI2015]线性代数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1054  Solved: 684[Submit][Statu ...

  2. bzoj 3996: [TJOI2015]线性代数 [最小割]

    3996: [TJOI2015]线性代数 题意:给出一个NN的矩阵B和一个1N的矩阵C.求出一个1*N的01矩阵A.使得 \(D=(A * B-C)* A^T\)最大.其中A^T为A的转置.输出D.每 ...

  3. [TJOI2015]线性代数(最小割)

    题目描述 给出一个N*N的矩阵B和一个1*N的矩阵C.求出一个1*N的01矩阵A.使得 D=(A*B-C)*A^T最大.其中A^T为A的转置.输出D 题解 观察上面那个式子发现,当一个bij有贡献时当 ...

  4. bzoj 3996 [TJOI2015]线性代数——最小割

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3996 b[ i ][ j ] 要计入贡献,当且仅当 a[ i ] = 1 , a[ j ] ...

  5. BZOJ3996 [TJOI2015]线性代数 【最小割】

    题目 给出一个NN的矩阵B和一个1N的矩阵C.求出一个1*N的01矩阵A.使得 D=(AB-C)A^T最大.其中A^T为A的转置.输出D 输入格式 第一行输入一个整数N,接下来N行输入B矩阵,第i行第 ...

  6. BZOJ3996 [TJOI2015]线性代数

    就是求$D = A \times B \times A^T - C \times A^T$ 展开也就是$$D = \sum_{i, j} A_i * A_j * B_{i, j} - \sum_{i} ...

  7. BZOJ3996 TJOI2015线性代数

    先把矩阵式子化简 原式=∑i=1n∑j=1nA[i]∗B[i][j]∗A[j]−∑i=1nA[i]∗C[i] 因此我们发现问题转化为选取一个点所获收益是B[i][j],代价是C[i][j] 这是一个最 ...

  8. BZOJ 3996 线性代数 最小割

    题意: 给出一个N*N的矩阵B和一个1*N的矩阵C.求出一个1*N的01矩阵A.使得 D=(A*B-C)*A^T最大.其中A^T为A的转置.输出D 分析: 这道题比较绕,我们需要看清题目中那个式子的本 ...

  9. BZOJ3996:[TJOI2015]线性代数(最大权闭合子图)

    Description 给出一个N*N的矩阵B和一个1*N的矩阵C.求出一个1*N的01矩阵A.使得 D=(A*B-C)*A^T最大.其中A^T为A的转置.输出D Input 第一行输入一个整数N,接 ...

随机推荐

  1. 【Topcoder 10107】TeamManagement

    Topcoder 10107 题意:给定一棵树,其中有些点是忠诚的,现在要选k个点,每个选择的联通块都必须包含一个忠诚的点,求包含某个点的概率. 思路:考虑树型\(dp\),\(dp(i,j,0/1, ...

  2. Linux下对inode和块的理解

    基本概念 首先讲下inode和块的基本概念.在Linux系统中,文件由元数据和数据块组成.数据块就是多个连续性的扇区(sector),扇区是文件存储的最小单位(每个512字节).块(block)的大小 ...

  3. SkylineGlobe Android 开发 面积计算示例代码

    SkylineGlobe Android 开发 面积计算示例代码: 如果之前熟悉SkylineGlobe桌面端的二次开发,看这些代码应该不难理解. package com.skyline.terrae ...

  4. openssl生成签名与验证签名

    继上一篇RSA对传输信息进行加密解密,再写个生成签名和验证签名. 一般,安全考虑,比如接入支付平台时,请求方和接收方要互相验证是否是你,就用签名来看. 签名方式一般两种,对称加密和非对称加密.对称加密 ...

  5. React-使用styled-components

    1.安装 npm install --save styled-components 2.简单使用 style.js: import styled from 'styled-components'; i ...

  6. C#实现一张塔松叶

    前段时间,Insus.NET有实现一组字符串在输出时,靠左或靠右对齐.<输出的字符靠右对齐>http://www.cnblogs.com/insus/p/7953304.html 现在In ...

  7. 【转】单KEY业务,数据库水平切分架构实践

    本文将以“用户中心”为例,介绍“单KEY”类业务,随着数据量的逐步增大,数据库性能显著降低,数据库水平切分相关的架构实践: 如何来实施水平切分 水平切分后常见的问题 典型问题的优化思路及实践 一.用户 ...

  8. JAVA消息确认机制之ACK模式

    JMS API中约定了Client端可以使用四种ACK模式,在javax.jms.Session接口中: AUTO_ACKNOWLEDGE = 1    自动确认 CLIENT_ACKNOWLEDGE ...

  9. (理论篇)从基础文件IO说起虚拟内存,内存文件映射,零拷贝

    为了快速构建项目,使用高性能框架是我的职责,但若不去深究底层的细节会让我失去对技术的热爱. 探究的过程是痛苦并激动的,痛苦在于完全理解甚至要十天半月甚至没有机会去应用,激动在于技术的相同性,新的框架不 ...

  10. Mysql之binlog日志说明及利用binlog日志恢复数据操作记录

    众所周知,binlog日志对于mysql数据库来说是十分重要的.在数据丢失的紧急情况下,我们往往会想到用binlog日志功能进行数据恢复(定时全备份+binlog日志恢复增量数据部分),化险为夷! 一 ...