传送门:
http://acm.hdu.edu.cn/showproblem.php?pid=5619
最小费用流题,构图的时候按照bc官方题解说得那样就OK了,即把每个修理师都拆成n个点,表示第1到第n个给谁修,每条边对应的费用通过它对答案贡献的时间来计算,比如倒数第二个,就是T[i][j]*2,包括自己修的和下一个等待的时间。然后源点向n个顾客连,n个顾客向拆出来的n*m个点连,然后这n*m个点都向汇点连,跑一遍最小费用流就ok了!
最小费用流的最小费用路算法:
步骤0:初始可行0流。 步骤1:如果不存在最小费用路,则计算结束,已经找到最小费用流;否则用最短路算法在残流网络中找从s到t的最小费用可增广路,转步骤2。 步骤2:沿找到的最小费用可增广路增流,并转步骤1。
code:
#include <stdio.h>
#include <string.h>
#define CLEAR(arr, val) memset(arr, val, sizeof(arr))
#define MAXN 55
#define MAXM 3000
#define INF 0xfffffff
bool vis[MAXM];
int n, src, end, res, edge_num, cost[MAXN][MAXN], edge_head[MAXM], d[MAXM], pre[MAXM], queue[MAXM<<4];
struct Edge {
int to, re, next, cap, cost;
} edge[MAXM*MAXM];
void add_edge(int from, int to, int cap, int cost)
{
edge[edge_num].to = to;
edge[edge_num].cap = cap;
edge[edge_num].cost = cost;
edge[edge_num].next = edge_head[from];
edge[edge_num].re = edge_num + 1;
edge_head[from] = edge_num++;
edge[edge_num].to = from;
edge[edge_num].cap = 0;
edge[edge_num].cost = -cost;
edge[edge_num].next = edge_head[to];
edge[edge_num].re = edge_num - 1;
edge_head[to] = edge_num++;
}
bool spfa()
{
int i, p, now, next, front, rear;
CLEAR(vis, false);
for (i = 0; i <= end; ++i)
d[i] = INF;
d[src] = 0;
front = rear = 0;
queue[rear++] = src;
vis[src] = true;
while (front != rear)
{
now = queue[front++];
//if (front == MAXN) // 循环队列
// front = 0;
vis[now] = false;
for (p = edge_head[now]; p != 0; p = edge[p].next)
{
next = edge[p].to;
if (edge[p].cap && d[next] > d[now] + edge[p].cost)
{
d[next] = d[now] + edge[p].cost;
pre[next] = p; // 记录边的编号..通过边回溯路径
if (!vis[next])
{
queue[rear++] = next;
// if (rear == MAXN)
// rear = 0;
vis[next] = true;
}
}
}
}
if (d[end] != INF)
return true;
return false;
}
void compute()
{
int i, p;
for (i = end; i != src; i = edge[edge[p].re].to)
{
p = pre[i];
edge[p].cap -= 1;
edge[edge[p].re].cap += 1;
res += edge[p].cost;
}
}
int main()
{
// freopen ("in.txt", "r", stdin);
int i, j, k, cases, m;
scanf("%d", &cases);
while (cases--)
{
edge_num = 1;
CLEAR(edge_head, 0);
scanf("%d%d", &m, &n);
for (i = 1; i <= n; ++i)
for (j = 1; j <= m; ++j)
scanf("%d", &cost[i][j]);
src = 0;
end = m * n + n + 1;
for (i = 1; i <= n; ++i)
add_edge(src, i, 1, 0);
for (i = 1; i <= n; ++i)
for (j = 1; j <= n; ++j)
for (k = 1; k <= m; ++k)
add_edge(i, n+(j-1)*m+k, 1, cost[i][k]*j);
for (i = n+1; i <= m*n+n; ++i)
add_edge(i, end, 1, 0);
res = 0;
while (spfa())
compute();
printf("%d\n", res);
}
return 0;
}