LINK:
http://acdream.info/problem?pid=1171
太弱没有想到用费用流做,每行每列至少选x个,相对立的是 每行每列至少选0个,至多N-x个的情况下选取的总和最大。
这就成了最大费用最大流。(要费用最大,流量一定最大了)
源点S和1....n (对应n行)建边流量为M-x,费用为0,n+1,n+2,....n+m(对应m列)和T建边,流量为N-x,费用为0
太弱没有想到用费用流做,每行每列至少选x个,相对立的是 每行每列至少选0个,至多N-x个的情况下选取的总和最大。
这就成了最大费用最大流。(要费用最大,流量一定最大了)
源点S和1....n (对应n行)建边流量为M-x,费用为0,n+1,n+2,....n+m(对应m列)和T建边,流量为N-x,费用为0
1....n和 n+1,n+2.....n+m分别建边流量为1,费用为num[i][j];
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define INF 1000000000
//typedef __int64 LL;
#define N 150
int n, m, num[N][N], S, T;
int tot, hh[N], nn[N], mm[N], sum;
int inq[N], dis[N], pre[N];
struct node
{
int u, v, flow, cost, next;
}edge[1000000];
void add(int u, int v, int flow,int cost)
{
edge[tot].u=u; edge[tot].v=v;
edge[tot].flow=flow; edge[tot].cost = cost;
edge[tot].next=hh[u]; hh[u] =tot++;
}
void add_(int u, int v, int flow, int cost)
{
add(u, v, flow, cost); add(v, u, 0, -cost);
}
void init()
{
memset(hh, -1, sizeof(hh));
tot = 0;
}
void creat()
{
init();
S=0; T= n+m+1;
for(int i=1; i<=n; i++)
{
add_(S, i, m-nn[i], 0);
}
for(int i=1; i<=m; i++)
{
add_(i+n, T, n-mm[i], 0);
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
add_(i, n+j, 1, num[i][j]);
}
}
}
int bfs()
{
queue<int> Q;
memset(inq, 0, sizeof(inq));
for(int i=0; i<=T; i++) dis[i] = -INF, pre[i] = -1;
dis[S] = 0;
Q.push(S); inq[S] = 1;
while(!Q.empty())
{
int u = Q.front(); Q.pop();
inq[u] = 0;
for(int i=hh[u]; i!=-1; i=edge[i].next)
{
int v = edge[i].v;
int flow = edge[i].flow, cost = edge[i].cost;
if(flow && dis[v] < dis[u] +cost)
{
dis[v] = dis[u] +cost;
pre[v] = i;
if(!inq[v])
{
inq[v] = 1; Q.push(v);
}
}
}
}
return dis[T]>=0;
}
int f()
{
int flow, cost;
flow = cost = 0 ;
while(bfs())
{
int tmp = INF;
for(int i=pre[T]; i!=-1; i=pre[edge[i].u])
{
tmp = min(tmp, edge[i].flow);
}
flow += tmp;
cost += dis[T]*tmp;
for(int i=pre[T]; i!=-1; i=pre[edge[i].u])
edge[i].flow -= tmp, edge[i^1].flow += tmp;
}
return sum - cost;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d%d",&n, &m);
sum = 0;
for(int i=1;i<=n; i++)
{
for(int j=1; j<=m; j++)
{
scanf("%d", &num[i][j]); sum += num[i][j];
}
}
for(int i=1; i<=n; i++) scanf("%d", &nn[i]);
for(int i=1; i<=m; i++) scanf("%d", &mm[i]);
creat();
printf("%d\n", f());
}
return 0;
}