放牧代码和思想
专注自然语言处理、机器学习算法
    愛しさ 優しさ すべて投げ出してもいい

AOJ 2251 Merry Christmas 题解 《挑战程序设计竞赛》

目录

AOJ 2251 Merry Christmas

国际圣诞礼品公司: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 题解 《挑战程序设计竞赛》

评论 欢迎留言

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

我的作品

HanLP自然语言处理包《自然语言处理入门》