ACdream-1171 Matrix sum, 最大费用最大流
来源:互联网 发布:网络课高级英语答案 编辑:程序博客网 时间:2024/04/29 21:31
Matrix sum
Time Limit: 8000/4000MS (Java/Others)Memory Limit: 128000/64000KB (Java/Others)
SubmitStatisticNext Problem
Problem Description
sweet和zero在玩矩阵游戏,sweet画了一个N * M的矩阵,矩阵的每个格子有一个整数。zero给出N个数Ki,和M个数Kj,zero要求sweet选出一些数,满足从第 i 行至少选出了Ki个数,第j列至少选出了Kj个数。 这些数之和就是sweet要付给zero的糖果数。sweet想知道他至少要给zero多少个糖果,您能帮他做出一个最优策略吗?
Input
首行一个数T(T <= 40),代表数据总数,接下来有T组数据。
每组数据:
第一行两个数N,M(1 <= N,M <= 50)
接下来N行,每行M个数(范围是0-10000的整数)
接下来一行有N个数Ki,表示第i行至少选Ki个元素(0 <= Ki <= M)
最后一行有M个数Kj,表示第j列至少选Kj个元素(0 <= Kj <= N)
Output
每组数据输出一行,sweet要付给zero的糖果数最少是多少
Sample Input
14 41 1 1 11 10 10 101 10 10 101 10 10 101 1 1 11 1 1 1
Sample Output
6
分析:
很容易想到二分图模型(n行左端点,m列右端点) --> 有上下界的费用流
每行每列取数的个数不能少于R[i] / C[i], 问取得数总和最小是多少Min_Sum?
转化为
每行每列取数的个数不多于 m-R[i] / n - C[i],问取得数总和最大是多少Max_Sum?
Min_Sum = All_Sum - Max_Sum
总数 - 最大费用最大流即可
这样就把有上下界的费用流问题转化为(只有上界)普通的费用流问题了。
#include<cstdio>#include<cstring>#include<queue>#include<vector>#include<algorithm>using namespace std;const int maxn = 202 + 10;const int INF = 1000000000;typedef long long LL;struct Edge { int from, to, cap, flow, cost;};struct MCMF { //<span style="font-size:14px;">最大费用最大流</span> int n, m, s, t; vector<Edge> edges; vector<int> G[maxn]; int inq[maxn]; // 是否在队列中 int d[maxn]; // Bellman-Ford int p[maxn]; // 上一条弧 int a[maxn]; // 可改进量 void init(int n) { this->n = n; for(int i = 0; i < n; i++) G[i].clear(); edges.clear(); } void AddEdge(int from, int to, int cap, int cost) { edges.push_back((Edge){from, to, cap, 0, cost}); edges.push_back((Edge){to, from, 0, 0, -cost}); m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BellmanFord(int s, int t, LL& ans) { for(int i = 0; i <= t; i++) d[i] = -INF; //与最小费用最大流相反(d[i]=INF) memset(inq, 0, sizeof(inq)); d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF; queue<int> Q; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = 0; for(int i = 0; i < G[u].size(); i++) { Edge& e = edges[G[u][i]]; if(e.cap > e.flow && d[e.to] < d[u] + e.cost) { <span style="font-family: Arial, Helvetica, sans-serif;">//与最小费用最大流相反(d[e.to] < d[u] + e.cost )</span> d[e.to] = d[u] + e.cost; p[e.to] = G[u][i]; a[e.to] = min(a[u], e.cap - e.flow); if(!inq[e.to]) { Q.push(e.to); inq[e.to] = 1; } } } } if(d[t] < 0) return false; //<span style="font-family: Arial, Helvetica, sans-serif;">与最小费用最大流相反(d[i]>=0)</span> ans += (LL)d[t] * (LL)a[t]; int u = t; while(u != s) { edges[p[u]].flow += a[t]; edges[p[u]^1].flow -= a[t]; u = edges[p[u]].from; } return true; } // 需要保证初始网络中没有负权圈 LL Mincost(int s, int t) { LL cost = 0; while(BellmanFord(s, t, cost)); return cost; }};MCMF g;int S, T;LL SUM;int a[60][60], R[60], C[60];void init(){ int n, m, i, j; scanf("%d%d", &n, &m); SUM = 0; for(i=1; i<=n; ++i) for(j=1; j<=m; ++j) { scanf("%d", &a[i][j]); SUM += a[i][j]; } for(i=1; i<=n; ++i) scanf("%d", &R[i]); for(i=1; i<=m; ++i) scanf("%d", &C[i]); S = 0, T = n + m + 1; g.init(T); for(i=1; i<=n; ++i) { g.AddEdge(S, i, m-R[i], 0); } for(i=1; i<=m; ++i) { g.AddEdge(i+n, T, n-C[i], 0); } for(i=1; i<=n; ++i) for(j=1; j<=m; ++j) { g.AddEdge(i, j+n, 1, a[i][j]); }}void solve(){ LL t = g.Mincost(S, T); printf("%I64d\n", SUM - t);}int main(){ int T; scanf("%d", &T); while(T--) { init(); solve(); } return 0;}
官方题解 最大费用最大流板子
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>using namespace std;const int E = 50010;const int oo = 0x7fffffff;const int N = 210;struct edge{ int next,v,flow,cost;}e[E];int head[N],cnt;queue<int> q;void addedge(int u,int v,int flow,int cost){ e[cnt].v = v; e[cnt].flow = flow; e[cnt].cost = cost; e[cnt].next = head[u]; head[u] = cnt ++;}void addEdge(int u,int v,int flow,int cost){ addedge(u,v,flow,cost); addedge(v,u,0, -cost);}int S,T;int ans;int a[N][N];void init(){ int n,m; scanf("%d%d",&n,&m); ans = 0; for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) { scanf("%d",&a[i][j]); ans += a[i][j]; } int R[N],C[N]; for(int i = 1; i <= n; i ++) scanf("%d",&R[i]); for(int i = 1; i <= m; i ++) scanf("%d",&C[i]); S = 0,T = n + m + 1; cnt = 0; memset(head,-1,sizeof(head)); for(int i = 1; i <= n; i ++) { addEdge(S,i,m - R[i],0); } for(int i = 1; i <= m; i ++) addEdge(i + n,T,n - C[i],0); for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) addEdge(i,j + n,1,a[i][j]);}int dis[N],cc[N],visit[N],pre[N],dd[N];int spfa(){ fill(dis,dis + T + 1, -oo); dis[S] = 0; pre[S] = -1; while(!q.empty()) q.pop(); q.push(S); while(!q.empty()) { int u = q.front(); q.pop(); visit[u] = 0; for(int i = head[u]; i != -1; i = e[i].next) { if(e[i].flow > 0 && dis[e[i].v] < dis[u] + e[i].cost) { dis[e[i].v] = dis[u] + e[i].cost; pre[e[i].v] = u; cc[e[i].v] = i; dd[e[i].v] = e[i].cost; if(!visit[e[i].v]) { q.push(e[i].v); visit[e[i].v] = 1; } } } } return dis[T] >= 0;}int argument(){ int aug = oo; int u,v; int ans = 0; for(u = pre[v = T]; v != S; v = u, u = pre[v]) if(e[cc[v]].flow < aug) aug = e[cc[v]].flow; for(u = pre[v = T]; v != S; v = u, u = pre[v]) { e[cc[v]].flow -= aug; e[cc[v] ^ 1].flow += aug; ans += dd[v] * aug; } return ans;}void mcmf(){ memset(visit,0,sizeof(visit)); while(spfa()) { int cost = argument(); if(ans < 0) break; ans -= cost; } printf("%d\n",ans);}int main(){ //freopen("choose.in","r",stdin); //freopen("choose.out","w",stdout); int t; scanf("%d",&t); for(int cas = 1; cas <= t; cas ++) { init(); mcmf(); } return 0;}
1 0
- ACdream-1171 Matrix sum, 最大费用最大流
- ACdream-1171 Matrix sum, 最大费用最大流
- [费用流] acdream 1171 Matrix sum
- ACDream 1171 最大费用流,流量不一定最大
- Acdream 1171 Matrix sum 上下界费用流
- ACdream 1171 Matrix sum (有界费用流)
- hdu 2686 Matrix 最大费用最大流
- hdu2686 Matrix 最大费用最大流
- Matrix (hdu 2686 最大费用最大流)
- acdream 1171 Matrix sum
- Kaka's Matrix Travels (最大费用流)
- 【最大费用流】Kaka's Matrix Travels
- hdu 2686 Matrix 最小费用最大流
- hdu 2686 Matrix(最大费用流)
- hdu 2686 Matrix【最大费用流】
- hdu 3376 Matrix Again【最大费用流】
- HDU 2686 Matrix(最大费用流)
- hdu 3376 Matrix Again 最大费用流
- POJ2112 Optimal Milking—网络流,最大流,二分
- ZOJ-1246
- UVA - 10004 Bicoloring (dfs和bfs两种解法)
- 用三分钟理解c语言sizeof
- git的简单使用
- ACdream-1171 Matrix sum, 最大费用最大流
- Mysql Innodb中undo-log和MVCC多版本一致性读 的实现
- python核心编程(第二版)参考答案(自制)--第六章·序列:字符串、列表和元组(Part2)
- bash: scp: command not found的原因及解决办法
- Java String类
- Android中Bitmap和Drawable
- 《数据结构》网上课堂(ing...)
- 链表2----删除链表中的同一数据
- reinterpret_cast