设为首页 加入收藏

TOP

ACdream-1171 Matrix sum, 最大费用最大流
2015-07-20 18:00:04 来源: 作者: 【 】 浏览:2
Tags:ACdream-1171 Matrix sum 最大 费用

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

1
4 4
1 1 1 1
1 10 10 10
1 10 10 10
1 10 10 10
1 1 1 1
1 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
  
   
#include
   
     #include
    
      #include
     
       #include
      
        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 { //
       最大费用最大流 int n, m, s, t; vector
       
         edges; vector
        
          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
         
           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) { 
          //与最小费用最大流相反(d[e.to] < d[u] + e.cost ) 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; //
          与最小费用最大流相反(d[i]>=0) 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 
  
   
#include 
   
     #include 
    
      #include 
     
       #include 
      
        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
       
         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; } 
       
      
     
    
   
  




】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇POJ 1609 Tiling Up Blocks. 下一篇uva10285 - Longest Run on a Sno..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: