热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

雨中避雨问题(HDU2389)——Hopcroft-Karp算法应用

题目描述:给定n把雨伞和m个人,t分钟后开始下雨。求在每个人只能使用一把雨伞的情况下,最多有多少人可以拿到雨伞。
题目描述

在一个场景中,有 n 把雨伞和 m 个人,t 分钟后开始下雨。每个人只能使用一把雨伞,且每把雨伞只能被一个人使用。目标是在下雨时,尽可能多的人能够拿到雨伞。

解题思路

该问题可以通过二分图的最大匹配来解决。具体步骤如下:

  1. 将问题建模为一个二分图,其中一边是雨伞,另一边是人。
  2. 计算每个人到每把雨伞的距离,如果某人在 t 分钟内可以到达某把雨伞,则在这两个节点之间建立一条边。
  3. 使用 Hopcroft-Karp 算法求解二分图的最大匹配。
代码实现
#include 
#include
#include
#include
#include
#define EDGE(int _to, int _next)
#define to(_to), next(_next)
#define ll long long
using namespace std;
typedef pair P;
const int maxn = 6050; // 存储的点最多是 n + m
int vis[maxn];
struct EDGE {
int to, next;
EDGE() {}
EDGE(int _to, int _next) : to(_to), next(_next) {}
} e[maxn * 1500];
int cnt, n, m, p, ca = 0, T, t;
int head[maxn], con[maxn], dep[maxn];
int x[maxn], y[maxn], s[maxn];
void add(int bg, int to) {
e[++cnt] = EDGE(to, head[bg]);
head[bg] = cnt;
}
void init() {
cnt = 0;
memset(head, -1, sizeof head);
memset(vis, 0, sizeof vis);
memset(con, -1, sizeof con); // 初始化 con 为 -1
cin >> t >> n;
for (int i = 1; i <= n; ++i) scanf("%d%d%d", &x[i], &y[i], &s[i]);
cin >> m;
for (int i = 1; i <= m; ++i) scanf("%d%d", &x[i + n], &y[i + n]);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
int w = (x[i] - x[j + n]) * (x[i] - x[j + n]) + (y[i] - y[j + n]) * (y[i] - y[j + n]);
int temp = t * s[i] * t * s[i];
if (temp >= w) add(i, j + n);
}
}
bool bfs() {
memset(dep, 0, sizeof dep);
queue q;
while (q.size()) q.pop();
for (int i = 1; i <= n; ++i)
if (con[i] == -1) q.push(i);
bool flag = 0;
while (q.size()) {
int u = q.front();
q.pop();
for (int i = head[u]; i != -1; i = e[i].next) {
if (!dep[e[i].to]) {
dep[e[i].to] = dep[u] + 1;
if (con[e[i].to] == -1) flag = 1;
else dep[con[e[i].to]] = dep[e[i].to] + 1, q.push(con[e[i].to]);
}
}
}
return flag;
}
bool dfs(int u) {
for (int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].to;
if (dep[v] != dep[u] + 1) continue;
dep[v] = 0;
if (con[v] == -1 || dfs(con[v])) {
con[u] = v;
con[v] = u;
return 1;
}
}
return 0;
}
void sol() {
int ans = 0;
while (bfs())
for (int i = 1; i <= n; ++i)
if (con[i] == -1 && dfs(i)) ans++;
printf("Scenario #%d:\n%d\n\n", ++ca, ans);
}
int main() {
cin >> T;
while (T--) {
init();
sol();
}
}

推荐阅读
  • 2022年4月15日的算法练习题,包括最长公共子序列和线段树的应用。 ... [详细]
  • 本题要求计算从起点到终点所有最短路径的总权重,使用SPFA算法进行求解。 ... [详细]
  • 题目描述:Balala Power! 时间限制:4000/2000 MS (Java/Other) 内存限制:131072/131072 K (Java/Other)。题目背景及问题描述详见正文。 ... [详细]
  • 题目描述墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令ÿ ... [详细]
  • ZOJ 2760 - 最大流问题
    题目链接:How Many Shortest Paths。题目描述:给定一个包含n个节点的有向图,通过一个n*n的矩阵来表示。矩阵中的a[i][j]值为-1表示从节点i到节点j无直接路径;否则,该值表示从i到j的路径长度。输入起点vs和终点vt,计算从vs到vt的所有不共享任何边的最短路径数量。如果起点和终点相同,则输出无穷大。 ... [详细]
  • 本文探讨了如何利用数组来构建二叉树,并介绍了通过队列实现的二叉树层次遍历方法。通过具体的C++代码示例,详细说明了构建及打印二叉树的过程。 ... [详细]
  • 深入解析C++ Atomic编程中的内存顺序
    在多线程环境中,为了防止多个线程同时修改同一数据导致的竞争条件,通常会使用内核级同步对象,如事件、互斥锁和信号量等。然而,这些方法往往伴随着高昂的上下文切换成本。本文将探讨如何利用C++11中的原子操作和内存顺序来优化多线程编程,减少不必要的开销。 ... [详细]
  • ED Tree HDU4812 点分治+逆元
    这道题非常巧妙!!!我们进行点分治的时候,算出当前子节点的所有子树中的节点,到当前节点节点的儿子节点的距离,如下图意思就是当前节点的红色节点,我们要求出红色节点的儿子节点绿色节点, ... [详细]
  • 深入理解Java反射机制
    本文将详细介绍Java反射的基础知识,包括如何获取Class对象、反射的基本过程、构造器、字段和方法的反射操作,以及内省机制的应用。同时,通过实例代码加深对反射的理解,并探讨其在实际开发中的应用。 ... [详细]
  • 基于OpenCV的小型图像检索系统开发指南
    本文详细介绍了如何利用OpenCV构建一个高效的小型图像检索系统,涵盖从图像特征提取、视觉词汇表构建到图像数据库创建及在线检索的全过程。 ... [详细]
  • 本文详细探讨了如何处理包含多种分隔符的字符串分割问题,并提供了一个高效的C++实现方案。 ... [详细]
  • 本文详细解析 Skynet 的启动流程,包括配置文件的读取、环境变量的设置、主要线程的启动(如 timer、socket、monitor 和 worker 线程),以及消息队列的实现机制。 ... [详细]
  • 本文介绍了一个基本的同步Socket程序,演示了如何实现客户端与服务器之间的简单消息传递。此外,文章还概述了Socket的基本工作流程,并计划在未来探讨同步与异步Socket的区别。 ... [详细]
  • LeetCode 102 - 二叉树层次遍历详解
    本文详细解析了LeetCode第102题——二叉树的层次遍历问题,提供了C++语言的实现代码,并对算法的核心思想和具体步骤进行了深入讲解。 ... [详细]
  • 深入理解线程池及其基本实现
    本文探讨了线程池的概念、优势及其在Java中的应用。通过实例分析不同类型的线程池,并指导如何构建一个简易的线程池。 ... [详细]
author-avatar
重庆车管所
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有