2018年4月月赛 Day2 工作分配问题 题解

2018年4月月赛 Day2 工作分配问题 题解

题目描述

设有 n 件工作分配给 n 个人。将工作 i 分配给第 j 个人所需的费用为c[i][j] 。试设计一个算法,为每一个人都分配 1 件不同的工作,并使总费用达到最小。

输入输出格式

输入格式

第一行有 1 个正整数 n 。接下来的 n 行,每行 n 个正整数,表示工作费用。

输出格式

一行,包含一个正整数,为计算出的最小总费用。

输入输出样例

输入样例#1:

1
2
3
4
3
10 2 3
2 3 4
3 4 5

输出样例#1:

1
9

说明

对于100%的数据,1<=n<=20,1<=c[i][j]<=100。

1月月赛的原题。

本题除了一月月赛中已经给出的dfs解,还可以有mcmf解。

代码:

dfs解:

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
#include<cstdio>
#include<iostream>
using namespace std;
bool v[30]={false};
long long ans=0;
int c[30][30],n;
void dfs(int x,int sum)
{
if(x>n)
{
if(sum<ans) ans=sum;
return;
}
if(ans>sum)
{
for(int i=1;i<=n;i++)
{
if(!v[i])
{
v[i]=true;
dfs(x+1,sum+c[x][i]);
v[i]=false;
}
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>c[i][j];
ans+=c[i][j];
}
}
dfs(1,0);
cout<<ans;
return 0;
}

感谢cyy dalao支援的MCMF解。

MCMF解:

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
#include <bits/stdc++.h>
using std::queue;
using std::min;
const int maxe = 2510;
const int maxn = 55;
const int inf = 0x3f3f3f3f;
struct Edge{
int u,v,f,c;
int next;
}e[maxe];
int head[maxn];
int ecnt;
void _AddEdge(int u,int v,int f,int c) {
e[ecnt].u = u;
e[ecnt].v = v;
e[ecnt].f = f;
e[ecnt].c = c;
e[ecnt].next = head[u];
head[u] = ecnt;
ecnt ++;
}
void AddEdge(int u,int v,int f,int c) {
_AddEdge(u,v,f,c);
_AddEdge(v,u,0,-c);
}
bool inq[maxn];
int dis[maxn];
int pre[maxn];
bool spfa(int s,int t) {
queue <int> q;
memset(dis,0x3f,sizeof(dis));
memset(inq,false,sizeof(inq));
memset(pre,-1,sizeof(pre));
dis[s] = 0;
inq[s] = true;
q.push(s);
while (!q.empty()) {
int cur = q.front();
q.pop();
inq[cur] = false;
for (int i=head[cur];~i;i=e[i].next) {
if (e[i].f > 0 && dis[cur] + e[i].c < dis[e[i].v]) {
dis[e[i].v] = dis[cur] + e[i].c;
pre[e[i].v] = i;
if (!inq[e[i].v]) {
q.push(e[i].v);
inq[e[i].v] = true;
}
}
}
}
return dis[t] != inf;
}
void MCMF(int s,int t,int &flow,int &cost) {
flow = 0;
cost = 0;
while (spfa(s,t)) {
int curFlow = inf;
for (int i=pre[t];~i;i=pre[e[i].u]) curFlow = min(curFlow,e[i].f);
for (int i=pre[t];~i;i=pre[e[i].u]) {
e[ i ].f -= curFlow;
e[i^1].f += curFlow;
}
cost += curFlow * dis[t];
}
}
/*
编号规则:
源点:0
汇点:1
人:2*n
任务:2*n+1
*/
int main() {
memset(head,-1,sizeof(head));
int n;
scanf("%d",&n);
for (int i=1;i<=n;i++) {
AddEdge( 0 ,2*i,1,0);
AddEdge(2*i+1, 1 ,1,0);
for (int j=1;j<=n;j++) {
int t;
scanf("%d",&t);
AddEdge(2*i,2*j+1,1,t);
}
}
int f,c;
MCMF(0,1,f,c);
printf("%d\n",c);
return 0;
}
--It's the end.Thanks for your read.--