Click : 题目链接
中文题。不翻译。
因为题目中问每行每列至少取多少个数,这是有下界最小费用流。。非常难搞。。 但可以转化一下,
从反的方向考虑。。就是每行每列最多取多少个, 这样反着建图,需要求的就是最大费用流了。
但需要注意的是, 这时候不需要满流, 因而需要对最大流最小费用流的模板的SPFA 写法进行改动。
我们在选择路径时,选择尽可能大的路径,这样才能保证费用最大。
然后其他建图就不难了。。
S连左边 n 个点 表示每行的限制, T连右边m个点表示列的限制
最后跑 SPFA 最大权路径的方式就OK了。。
要注意 dist 改成 -oo ,
#include <cstdio>
#include <cstdlib>
#include <map>
#include <set>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <sstream>
#include <math.h>
#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pLL pair<long long ,long long>
#define pb(x) push_back(x)
#define rep(i,j,k) for(int i = j; i < k;i++)
#define MAX(x,a) x=((x)<(a))?(a):(x);
#define MIN(x,a) x=((x)>(a))?(a):(x);
using namespace std;
int sumFlow;
const int MAXN = 502;
const int MAXM = 10002;
const int INF = 1000000000;
struct Edge
{
int u, v, cap, cost;
int next;
}edge[MAXM<<2];
int NE;
int head[MAXN], dist[MAXN], pp[MAXN];
bool vis[MAXN];
void init()
{
NE = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int cap, int cost)
{
edge[NE].u = u; edge[NE].v = v; edge[NE].cap = cap; edge[NE].cost = cost;
edge[NE].next = head[u]; head[u] = NE++;
edge[NE].u = v; edge[NE].v = u; edge[NE].cap = 0; edge[NE].cost = -cost;
edge[NE].next = head[v]; head[v] = NE++;
}
bool SPFA(int s, int t, int n)
{
int i, u, v;
queue <int> qu;
memset(vis,false,sizeof(vis));
memset(pp,-1,sizeof(pp));
for(i = 0; i <= n; i++) dist[i] = -INF;
vis[s] = true; dist[s] = 0;
qu.push(s);
while(!qu.empty())
{
u = qu.front(); qu.pop(); vis[u] = false;
for(i = head[u]; i != -1; i = edge[i].next)
{
v = edge[i].v;
if(edge[i].cap && dist[v] < dist[u] + edge[i].cost)
{
dist[v] = dist[u] + edge[i].cost;
pp[v] = i;
if(!vis[v])
{
qu.push(v);
vis[v] = true;
}
}
}
}
return dist[t] >= 0;
}
int MCMF(int s, int t, int n) // minCostMaxFlow
{
int flow = 0; // 总流量
int i, minflow, mincost;
mincost = 0;
while(SPFA(s, t, n))
{
minflow = INF+1 ;
for(i = pp[t]; i != -1; i = pp[edge[i].u])
if(edge[i].cap < minflow)
minflow = edge[i].cap;
flow += minflow;
for(i = pp[t]; i != -1; i = pp[edge[i].u])
{
edge[i].cap -= minflow;
edge[i^1].cap += minflow;
}
mincost += dist[t] * minflow;
}
sumFlow = flow; // 题目需要流量,用于判断
return mincost;
}
int a[55][55];
int R[55],C[55];
int gg[55][55];
int main()
{
int n, m;
int u, v, c;
int t;
scanf("%d",&t);
while (t--)
{
scanf("%d%d", &n, &m);
init();
int S = 0;
int T = n + m + 1;
int ans = 0;
rep(i,1,n+1)
rep(j,1,m+1)
scanf("%d",&a[i][j]), ans+=a[i][j];
rep(i,1,n+1) scanf("%d",&R[i]);
rep(i,1,m+1) scanf("%d",&C[i]);
rep(i,1,n+1){
addedge(S,i,m-R[i],0);
}
rep(i,1,m+1)
addedge(i+n,T,n-C[i],0);
int zz = NE;
rep(i,1,n+1)
rep(j,1,m+1){
addedge(i,j+n,1,a[i][j]);
}
int sdf = NE;
int cc=MCMF(S,T,T+1);
ans -= cc;
printf("%d\n",ans);
}
return 0;
}