BZOJ3996 [TJOI2015]线性代数 【最小割】
2018-03-09 13:35
513 查看
题目
给出一个NN的矩阵B和一个1N的矩阵C。求出一个1*N的01矩阵A.使得
D=(AB-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
题解
我们将式子化简,就是:
\(\sum_{i = 1}^{n} \sum_{j = 1}^{n} Bij * Ai * Aj - \sum_{i}^{n} Ci * Ai\)
相当于,有n个物品,选择每个物品都有代价,任意两个物品同时选择时都有价值,求最大价值
用最小割解决
对于任意两个点i和j,建一个新点u,两点向u连边INF,u向T连边,容量为两个物品选择的权值
S向所有点连边,容量为该物品价值
我们假设一开始拥有所有价值
这样一来,要割去,每个点要么要花费其代价S->u,要么花费其与其它物品的共同代价u->T
#include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<cstring> #include<algorithm> #define LL long long int #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) #define REP(i,n) for (int i = 1; i <= (n); i++) #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts(""); using namespace std; const int maxn = 300005,maxm = 5000005,INF = 1000000000; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();} while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();} return out * flag; } int h[maxn],ne = 2,n,m; struct EDGE{int to,nxt,f;}ed[maxm]; inline void build(int u,int v,int w){ ed[ne] = (EDGE){v,h[u],w}; h[u] = ne++; ed[ne] = (EDGE){u,h[v],0}; h[v] = ne++; } int d[maxn],vis[maxn],S,T,cur[maxn]; bool bfs(){ for (int i = S; i <= T; i++) vis[i] = 0,d[i] = INF; queue<int> q; q.push(S); vis[S] = true; d[S] = 0; int u; while (!q.empty()){ u = q.front(); q.pop(); Redge(u) if (ed[k].f && !vis[to = ed[k].to]){ d[to] = d[u] + 1; vis[to] = true; q.push(to); } } return vis[T]; } int dfs(int u,int minf){ if (u == T || !minf) return minf; int f,flow = 0,to; if (cur[u] == -1) cur[u] = h[u]; for (int& k = cur[u]; k; k = ed[k].nxt) if (d[to = ed[k].to] == d[u] + 1 && (f = dfs(to,min(minf,ed[k].f)))){ ed[k].f -= f; ed[k ^ 1].f += f; flow += f; minf -= f; if (!minf) break; } return flow; } int maxflow(){ int flow = 0; while (bfs()){ memset(cur,-1,sizeof(cur)); flow += dfs(S,INF); } return flow; } int main(){ n = read(); S = 0; T = n + n * n + 1; int x,ans = 0,id = n; for (int i = 1; i <= n; i++){ for (int j = 1; j <= n; j++){ ans += (x = read()); id++; build(i,id,INF); build(j,id,INF); build(id,T,x); } } for (int i = 1; i <= n; i++) build(S,i,read()); printf("%d\n",ans - maxflow()); return 0; }
相关文章推荐
- bzoj3996 [TJOI2015]线性代数
- bzoj3996 [TJOI2015]线性代数
- ●BZOJ 3996 [TJOI2015]线性代数
- 【BZOJ】3996: [TJOI2015]线性代数
- bzoj3996 [TJOI2015]线性代数
- bzoj 3996: [TJOI2015]线性代数
- BZOJ 3996 [TJOI 2015] 线性代数 解题报告
- bzoj 3996: [TJOI2015]线性代数
- bzoj3996 [TJOI2015]线性代数(最小割)
- BZOJ 3996: [TJOI2015]线性代数 最大权闭合子图 最小割
- BZOJ 3996 TJOI 2015 线性代数 最小割
- bzoj 3996: [TJOI2015]线性代数 [最小割]
- [BZOJ3996]TJOI2015线性代数|最小割
- 3996: [TJOI2015]线性代数
- 【BZOJ3996】线性代数(TJOI2015)-最小割
- 【BZOJ】【TJOI2015】线性代数
- 【BZOJ3996】【TJOI2015】线性代数 最小割
- 【BZOJ 3996】 3996: [TJOI2015]线性代数 (最小割)
- bzoj 3996: [TJOI2015]线性代数 最小割
- 【BZOJ3996】[TJOI2015]线性代数【最小割】