HDU 5619 Jam's store

问题描述

Jam不好好学习,然后就去帮别人修电脑了,在一家店里,有\(M\)个店员,现在有\(N\)个顾客,给出每个顾客对应给每个店员的修电脑的时间为\(T_{ij}\),问所有顾客要等待的最少时间。当然,一个顾客在某个店员那里完成之后,那个店员才会执行下一个顾客的任务

输入描述

第一行\(T(1 \leq T \leq 100)\),表示\(T\)组数据。 接下来\(T\)组数据: 每组数据第一行为\(M,N(1 \leq M,N \leq 20)\)表示店员数和顾客数 接下来\(N\)行\(M\)列,每个整数表示第\(i\)个顾客找第\(j\)个店员的时间\((1 \leq T_{ij} \leq 1000)\)

输出描述

输出一个数,表示用时总时间

输入样例

1 4 3 4 4 1 5 8 2 5 6 4 5 10 5

输出样例

7

Hint

第1个顾客选择第3个员工 第2个顾客选择第2个员工 第3个顾客选择第1个员工 一共花费4+2+1=7

Solution

这道题是很有意思的网络流题目,建图非常之经典。

我们把每个修电脑的都拆成N个点,第i个点表示这个人是倒数第几个去找的他。

他对答案的影响是这个人等待时间加上他后面一排人(倒数第i个以后有i个人)等待时间。

那么每个人建一条边,流量为1,费用为\(T_{ij}*i\)的边就可以了。

Code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
#include <cstdio>
#include <queue>
const int INF = 1<<30;
int getint() {
	int r = 0, k = 1; char c = getchar();
	for (; c < '0' || c > '9'; c = getchar()) if (c == '-') k = -1;
	for (; '0' <= c && c <= '9'; c = getchar()) r = r * 10 - '0' + c;
	return r * k;
}
const int maxn = 1005;
const int maxnode = maxn*2+10;
const int maxe = 80010;
struct edge_type {
	int to, next, r, c;
} edge[maxe];
int h[maxnode], cnte = 1;
int S, T;
int n, m;
void ins(int u, int v, int f, int c) {
	++cnte;
	edge[cnte].to = v;
	edge[cnte].next = h[u];
	edge[cnte].r = f;
	edge[cnte].c = c;
	h[u] = cnte;
	++cnte;
	edge[cnte].to = u;
	edge[cnte].next = h[v];
	edge[cnte].r = 0;
	edge[cnte].c = -c;
	h[v] = cnte;
}
using namespace std;
queue<int> Q;
int dis[maxnode], pre[maxnode], a[maxnode];
bool vis[maxnode];
bool SPFA(int S, int T, int &flow, int &cost){
	while (!Q.empty()) Q.pop();
	for (int i = S; i <= T; ++i) vis[i] = false, dis[i] = INF;
	dis[S] = 0;
	Q.push(S);
	vis[S] = true;
	a[S] = INF;
	pre[S] = 0;
	int now;
	while (!Q.empty()) {
		now = Q.front(); Q.pop();
		vis[now] = false;
		for (int i = h[now]; i; i = edge[i].next) {
			if (edge[i].r && dis[edge[i].to] > dis[now] + edge[i].c) {
				dis[edge[i].to] = dis[now] + edge[i].c;
				pre[edge[i].to] = i;
				a[edge[i].to] = min(a[now], edge[i].r);
				if (!vis[edge[i].to]) {
					Q.push(edge[i].to);
					vis[edge[i].to] = true;
				}
			}
		}
	}
	if (dis[T] == INF) return false;
	flow += a[T];
	cost += a[T] * dis[T];
	for (now = T; now != S; now = edge[pre[now]^1].to) {
		edge[pre[now]].r -= a[T];
		edge[pre[now]^1].r += a[T];
	}
	return true;
}
int ans1, ans2;
int MCMF(int S, int T) {
	int flow = 0, cost = 0;
	while (SPFA(S, T, flow, cost));
	ans1 = flow; ans2 = cost;
	return cost;
}
int TT[25][25];
void readdata() {
	m = getint(); n = getint();
	S = 1; T = m*n+10+n;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j)
			TT[i][j] = getint();
	for (int i = 1; i <= n; ++i) {
		ins(S, i+n*m+5, 1, 0);
		for (int j = 1; j <= m; ++j)
			for (int k = 1; k <= n; ++k)
				ins(i+n*m+5, (k-1)*m+j+1, 1, TT[i][j]*k);
	}
	for (int j = 1; j <= m; ++j)
		for (int k = 1; k <= n; ++k)
			ins((k-1)*m+j+1, T, 1, 0);
}
void init() {
	for (int i =0; i <= 1000; ++i) h[i] = 0;
	cnte = 1;
}

int main() {
	int TTT = getint();
	while (TTT--) {
		init();
		readdata();
		MCMF(S, T);
		printf("%d\n", ans2);
	}
	return 0;
}