
国际圣诞礼品公司:International Christmas Present Company (ICPC)是一家圣诞礼品快递公司,由M条路连起的N户人家发起了L次订单,分别要求在时刻t准时将礼物送到p处。求最少需要几个圣诞老人?
3.5借助水流解决问题的网络流
二分图匹配
不妨考虑最坏情况,L个订单分配给L个圣诞老人。再考虑如何省下人力,假设处理完订单Q_i,还有时间步行到Q_j指定的地址,那么这两个订单可以交给同一个人处理。于是建立二分图,可以合并的订单之间连一条边,最小边覆盖即为所求。
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
////////////////////////最大流开始//////////////////////////////////////
#define MAX_V 1000 * 2 + 16
int V; // 顶点数
vector<int> G[MAX_V]; // 图的邻接表
int match[MAX_V]; // 所匹配的顶点
bool used[MAX_V]; // DFS中用到的访问标记
// 向图中增加一条连接u和v的边
void add_edge(int u, int v)
{
G[u].push_back(v);
G[v].push_back(u);
}
// 通过DFS寻找增广路
bool dfs(int v)
{
used[v] = true;
for (vector<int>::iterator it = G[v].begin(); it != G[v].end(); ++it)
{
int u = *it, w = match[u];
if (w < 0 || !used[w] && dfs(w))
{
match[v] = u;
match[u] = v;
return true;
}
}
return false;
}
// 求解二分图的最大匹配
int bipartite_matching()
{
int res = 0;
memset(match, -1, sizeof(match));
for (int v = 0; v < V; ++v)
{
if (match[v] < 0)
{
memset(used, 0, sizeof(used));
if (dfs(v))
{
++res;
}
}
}
return res;
}
void clear()
{
for (int i = 0; i < V; ++i)
{
G[i].clear();
}
}
///////////////////////////////最大流结束/////////////////////////////////////
#define MAX_N 100
#define MAX_L 1000
#define INF 0x3f3f3f3f
int distance_matrix[MAX_N][MAX_N]; // 两点间最短路
int p[MAX_L], t[MAX_L]; // 房间编号,时刻
bool update_min(int& v, const int& t)
{
if (t < v)
{
v = t;
return true;
}
return false;
}
///////////////////////////SubMain//////////////////////////////////
int main(int argc, char *argv[])
{
int N, M, L;
while (scanf("%d%d%d", &N, &M, &L) != EOF && N)
{
V = L * 2;
clear();
memset(distance_matrix, INF, sizeof(distance_matrix));
for (int _ = 0; _ < M; ++_)
{
int u, v, d;
scanf("%d%d%d", &u, &v, &d);
distance_matrix[u][v] = distance_matrix[v][u] = d;
}
for (int i = 0; i < L; ++i)
{
scanf("%d%d", p + i, t + i);
}
// warshall_floyd 两点间最短路
for (int k = 0; k < N; ++k)
{
distance_matrix[k][k] = 0;
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < N; ++j)
{
update_min(distance_matrix[i][j], distance_matrix[i][k] + distance_matrix[k][j]);
}
}
}
for (int i = 0; i < L; ++i)
{
for (int j = 0; j < L; ++j)
{
if (i != j && t[i] + distance_matrix[p[i]][p[j]] <= t[j])
{
add_edge(2 * i, 2 * j + 1); // 可以在i之后处理j,连一条边
}
}
}
printf("%d\n", L - bipartite_matching());
}
return 0;
}
///////////////////////////End Sub//////////////////////////////////

知识共享署名-非商业性使用-相同方式共享:码农场 » AOJ 2251 Merry Christmas 题解 《挑战程序设计竞赛》
码农场