描述
给你一个m x n (1 <= m, n <= 100)的矩阵A (0<=aij<=10000),要求在矩阵中选择一些数,要求每一行,每一列都至少选到了一个数,使得选出的数的和尽量的小。
输入
多组测试数据。首先是数据组数T
对于每组测试数据,第1行是两个正整数m, n,分别表示矩阵的行数和列数。
接下来的m行,每行n个整数,之间用一个空格分隔,表示矩阵A的元素。
输出
每组数据输出一行,表示选出的数的和的最小值。
数据范围
小数据:1 <= m, n <= 5
大数据:1 <= m, n <= 100
2 3 3 1 2 3 3 1 2 2 3 1 5 5 1 2 3 4 5 5 1 2 3 4 4 5 1 2 3 3 4 5 1 2 2 3 4 5 1
Case 1: 3 Case 2: 5
题意:给出一个矩阵,在矩阵中抽数,使得每一行每一列都有被取到。取出来的数和最小
思路:最小费用流。超级源点连向行,流量为c-1,费用0。列连向超级汇点,流量为r-1,费用为0。行和列相连,流量为1,费用为-key。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define maxn 1800 #define maxm 38000 #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 dis[t]; } int MinCostFlow(int s,int t) { int cost = 0; while(1) { int add = spfa(s,t); if(add >= 0) break; cost += add; for(int i = t;i != s;i = pre[i]) { ww[pos[i]] -= 1; ww[pos[i]^1] += 1; } } return cost; } int main() { //freopen("in.txt","r",stdin); int t,cas = 0; scanf("%d",&t); while(t--) { int r,c; int sum = 0; scanf("%d%d",&r,&c); for(int i = 1;i <= r;i++) { for(int j = 1;j <= c;j++) { scanf("%d",&key[i][j]); sum += key[i][j]; } } e = 0; memset(first,-1,sizeof(first)); for(int i = 1;i <= r;i++) addEdge(0,i,c-1,0); for(int i = r+1;i <= r+c;i++) addEdge(i,r+c+1,r-1,0); for(int i = 1;i <= r;i++) { for(int j = r+1;j <= r+c;j++) { addEdge(i,j,1,-key[i][j-r]); } } int ans = -MinCostFlow(0,r+c+1); ans = sum - ans; printf("Case %d: %d\n",++cas,ans); } return 0; }