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
思路:超源向行连边,容量为m-Ki,费用为0.列向超汇连边,容量为n-Kj,费用为0.行列连容量为1,费用为-key的边。当spfa找到的路径cost>=0就可停止。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define maxn 3800 #define maxm 48000 #define inf 0x3f3f3f3f int first[maxn]; int key[108][108]; int vv[maxm],ww[maxm],nxt[maxm],cst[maxm]; int e; int pre[maxn],pos[maxn]; int dis[maxn],que[maxn*10]; bool vis[maxn]; inline int min(int a,int b) { return a > b?b:a; } void addEdge(int u,int v,int w,int cost) { vv[e] = v; ww[e] = w; cst[e] = cost; nxt[e] = first[u]; first[u] = e++; vv[e] = u; ww[e] = 0; cst[e] = -cost; nxt[e] = first[v]; first[v] = e++; } int spfa(int s,int t) { memset(pre,-1,sizeof(pre)); memset(vis,0,sizeof(vis)); int head,tail; head = tail = 0; for(int i = 0;i < maxn;i++) dis[i] = inf; que[tail++] = s; pre[s] = s; dis[s] = 0; vis[s] = 1; while(head < tail) { int u = que[head++]; vis[u] = 0; for(int i = first[u];i != -1;i = nxt[i]) { int v = vv[i]; if(ww[i] > 0 && dis[u] + cst[i] < dis[v]) { dis[v] = dis[u] + cst[i]; pre[v] = u; pos[v] = i; if(!vis[v]) { vis[v] = 1; que[tail++] = v; } } } } return pre[t] != -1; } int MinCostFlow(int s,int t,int flow) { int cost = 0; int nowflow = 0; while(spfa(s,t)) { int f = inf; for(int i = t;i != s;i = pre[i]) if(ww[pos[i]] < f) f = ww[pos[i]]; if(dis[t] >= 0) break; f = min(flow - nowflow,f); nowflow += f; cost += dis[t]*f; for(int i = t;i != s;i = pre[i]) { ww[pos[i]] -= f; ww[pos[i]^1] += f; } if(nowflow == flow) break; } return cost; } int main() { //freopen("in.txt","r",stdin); int t; scanf("%d",&t); while(t--) { int n,m; scanf("%d%d",&n,&m); e = 0; memset(first,-1,sizeof(first)); int sum = 0; for(int i = 1;i <= n;i++) { for(int j = 1;j <= m;j++) { int a; scanf("%d",&a); sum += a; addEdge(i,n+j,1,-a); } } for(int i = 1;i <= n;i++) { int a; scanf("%d",&a); addEdge(0,i,m-a,0); } for(int i = 1;i <= m;i++) { int a; scanf("%d",&a); addEdge(n+i,n+m+1,n-a,0); } int fuck = MinCostFlow(0,n+m+1,inf); printf("%d\n",sum+fuck); } }