题解_P1525 [NOIP2010 提高组] 关押罪犯

news/2024/11/15 21:00:36/文章来源:https://www.cnblogs.com/hellohebin/p/18333807

目录
  • [NOIP2010 提高组] 关押罪犯
    • 题目背景
    • 题目描述
    • 输入格式
    • 输出格式
    • 样例 #1
      • 样例输入 #1
      • 样例输出 #1
    • 提示
    • 题解
      • 思路分析
      • 程序实现

[NOIP2010 提高组] 关押罪犯

题目背景

NOIP2010 提高组 T3

题目描述

S 城现有两座监狱,一共关押着 \(N\) 名罪犯,编号分别为 \(1\sim N\)。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为 \(c\) 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为 \(c\) 的冲突事件。

每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到 S 城 Z 市长那里。公务繁忙的 Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。

在详细考察了 \(N\) 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。

那么,应如何分配罪犯,才能使 Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?

输入格式

每行中两个数之间用一个空格隔开。第一行为两个正整数 \(N,M\),分别表示罪犯的数目以及存在仇恨的罪犯对数。接下来的 \(M\) 行每行为三个正整数 \(a_j,b_j,c_j\),表示 \(a_j\) 号和 \(b_j\) 号罪犯之间存在仇恨,其怨气值为 \(c_j\)。数据保证 \(1<a_j\leq b_j\leq N, 0 < c_j\leq 10^9\),且每对罪犯组合只出现一次。

输出格式

共一行,为 Z 市长看到的那个冲突事件的影响力。如果本年内监狱中未发生任何冲突事件,请输出 0

样例 #1

样例输入 #1

4 6
1 4 2534
2 3 3512
1 2 28351
1 3 6618
2 4 1805
3 4 12884

样例输出 #1

3512

提示

输入输出样例说明

罪犯之间的怨气值如下面左图所示,右图所示为罪犯的分配方法,市长看到的冲突事件影响力是 \(3512\)(由 \(2\) 号和 \(3\) 号罪犯引发)。其他任何分法都不会比这个分法更优。

数据范围

对于 \(30\%\) 的数据有 \(N\leq 15\)

对于 \(70\%\) 的数据有 \(N\leq 2000,M\leq 50000\)

对于 \(100\%\) 的数据有 \(N\leq 20000,M\leq 100000\)

题解

思路分析

【方法1】二分答案+染色二分图

题目中有明显的求最大值最小的概念,于是可以考虑二分答案,对于最大值检查可以采用二分图染色。

【方法2】贪心+并查集(带权/扩展域名)

由于题目的答案一定是其中的某一条边长,怎么使得该边长最小?
可以想到每次先将较大值放入不同监狱,如果可以放置,那么后面的答案一定更小;如果不能放置,则其就是答案。

所以可以按照边长排序,降序合并每条边即可。

合并的时候有两种策略

  1. 带权并查集:使用权值来维护当前元素与根节点元素的种类关系,如 d[u]=0表示 u与root是同类,d[u]=1表示不同类。带权并查集的find和union操作需要适当更新权值数组d[u];
int find(int u) {if (u != p[u]) {int fu = p[u];p[u] = find(p[u]);d[u] = (d[u] + d[fu]) % 2;}return p[u];
}
void union_(int u, int v) {int a = find(u), b = find(v);p[a] = b;d[a] = ((d[v] - d[u] + 2) % 2 + 1) % 2;
}
  1. 扩展域并查集:将并查集的规模扩展为原来的两倍,前一半用于维护朋友关系,后一半用于维护敌人关系。如 (u,u+n) 是敌人,(v,v+n) 是敌人,当 (u,v)是敌人的时候,根据敌人的敌人是朋友,可以将 u 与 u的敌人(v)的敌人(v+n)合并,即合并 (u, v+n);同理合并 (v, u+n)。

程序实现

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e4 + 10, M = 1e5 + 10, INF = 0x3f3f3f3f;
int n, m, p[N << 1], d[N << 1];
struct T {int u, v, w;bool operator<(const T& t) const { return w < t.w; }
} g[M];// -------------------
// 二分答案+染色二分图
vector<int> G[N];
int color[N], flag;
void dfs(int u, int c) {color[u] = c;for (auto v : G[u]) {if (!color[v]) dfs(v, ~c);else if (color[v] == c) flag = 0;}
}
bool chk(int k) {  // 将边权 >k 的建图,检查是否可以进行二分图染色for (int i = 1; i <= n; i++) G[i].clear();for (int i = k + 1; i <= m; i++) {int u = g[i].u, v = g[i].v;G[u].push_back(v), G[v].push_back(u);}flag = 1, memset(color, 0x00, sizeof color);for (int i = 1; i <= n && flag; i++)if (!color[i]) dfs(i, 1);return flag;
}
int solve1() {int l = 0, r = m, ans = 0;while (l <= r) {int mid = l + r >> 1;chk(mid) ? r = mid - 1, ans = mid : l = mid + 1;}return g[ans].w;
}
// -------------------
int find(int u) {if (u != p[u]) {int fu = p[u];p[u] = find(p[u]);d[u] = (d[u] + d[fu]) % 2;}return p[u];
}
// 带权并查集
// d[i]表示 i与根节点的关系:0-朋友,1-敌人
int solve2() {for (int i = 0; i <= n; i++)p[i] = i, d[i] = 0;for (int i = m; i >= 1; i--) {int u = g[i].u, v = g[i].v;int a = find(u), b = find(v);if (a == b && (d[u] - d[v] + 4) % 2 == 0)return g[i].w;p[a] = b;d[a] = ((d[v] - d[u] + 2) % 2 + 1) % 2;}return 0;
}
// 扩展域并查集
// 敌人的敌人是朋友:u,u+n是敌人,u,v是敌人,将u放入v的敌人v+n的集合
int solve3() {for (int i = 0; i <= n * 2; i++)p[i] = i;for (int i = m; i >= 1; i--) {int u = g[i].u, v = g[i].v;int a = find(u), b = find(v);if (a == b)return g[i].w;p[a] = find(v + n);p[b] = find(u + n);}return 0;
}
int main() {cin >> n >> m;for (int i = 1, u, v, w; i <= m; i++)cin >> u >> v >> w, g[i] = {u, v, w};sort(g + 1, g + 1 + m);// cout << solve1() << endl;//AC// cout << solve2() << endl;//ACcout << solve3() << endl;  // ACreturn 0;
}
/*
P1525 [NOIP2010 提高组] 关押罪犯
https://www.luogu.com.cn/problem/P1525in:
4 6
1 4 2534
2 3 3512
1 2 28351
1 3 6618
2 4 1805
3 4 12884out:3512
*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/774448.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

架构与思维:DNS在架构中的使用

1 介绍 DNS(Domain Name System,域名系统)是一种服务,它是域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访问互联网,而不用去记住能够被机器直接读取的IP地址数串。 简单来说,DNS就是一个将我们输入的网址(比如www.baidu.com )转换成对应的IP地址(比如19…

python3 unittest+BeautifulReport单个进程输出多个测试报告

最近一个项目中需要由于输出的案例内容非常多(上万条),导致BeautifulReport输出的报告内容非常大(几百兆)。浏览器无法正常处理这么大的测试报告,就算打开了,也不方便阅读和处理,因此需要将报告分成多个输出。 经修改代码,发现单个进程内输出多个测试报告出现问题:第…

windows11解决visual c++6.0 打开提示不兼容弹窗问题

在Windows11系统中,打开Visual C++ 6.0 编辑器,会弹出不兼容弹窗,如图所示下面将给出解决办法,实测有效。 步骤1:重命名MSDEV.EXE文件 步骤2:修改“兼容模式”配置 步骤3:修改“目标”输入框内容 步骤4:重新启动软件人生如逆旅 我亦是行人

零基础快速上手STM32开发(手把手保姆级教程)

1 前言 作为一名嵌入式工程师,STM32 是必须要学习的一款单片机,同时这款单片机资料足够多,而且比较简单,非常适合初学者入门。 STM32 是一款由 STMicroelectronics 公司开发的 32 位微控制器,由于其强大的处理能力和广泛的应用领域,如嵌入式系统、物联网设备、机器人等,…

比网盘、FTP更好用的数据摆渡工具是什么?

企业进行网络隔离后,数据在隔离网间交换时就产生了数据摆渡需求,常见的数据摆渡工具包括移动U盘、网盘、FTP等,企业通常选择网盘、FTP来进行日常的数据摆渡操作。但网盘和FTP在数据摆渡上均存在不同程度的缺陷,具体表现在: 数据量限制:网盘一般面向办公文档型数据,系统往…

全文检索方案

1. 方案概述 本文旨在设计全文搜索功能,包括数据的存储、数据权限、数据接口、数据模型等,从整体设计全文检索方案。 2. 解决方案 全文搜索解决方案主要包含两部分,数据的存储及数据的查询展示,其中数据存储方面,主要分为业务数据存储及附件存储;而数据查询展示主…

课堂笔记 - C++ 位运算符

C++位运算符 在C++当中,有六个位操作运算符,二进制来进行操作 & 按位与 1 & 0 = 0 | 按位或 1 | 0 = 1 ~ 按位非 0 取反变成 1 1取反变成0 ^ 异或 相同为0 不同为1 << 左移 二进制往左靠,右侧补零 >> 右移 二进制往右靠,左侧补零 0xff = 很明…

netty核心流程(二):客户端与服务端的读写过程

连接成功建立后,客户端是如何向服务端发送请求的? 由于内部源码的调用过于复杂,我们只分析有代表性的代码。在 AbstractChannel 类中我们可以看到: wirte() 方法最后会把发送的数据 msg 放入 addMessage() 方法中,这个方法是做什么的呢? 原来把要发送数据放入一个缓冲链…

P1168 中位数题解

题目链接:https://www.luogu.com.cn/problem/P1168 题目描述:给定一个长度为 N 的非负整数序列 A,对于前奇数项求中位数。 思路讲解:最简单的想法就是每次取我们要的那段数组然后排序在输出中位数。确实可以,但是太慢了,直接超时。那就是说要缩短时间,那就可以直接用到堆…

Qt/C++音视频开发80-ffmpeg实现srt推拉流/实时性非常好/音视频同步/支持格式众多

一、前言 目前互联网上的视频直播有两种,一种是基于RTMP协议的直播,这种直播方式上行推流使用RTMP协议,下行播放使用RTMP,HTTP+FLV或者HLS,直播延时一般大于3秒,广泛应用秀场、游戏、赛事和事件直播,满足了对交互要求不高的场景;另一种是WebRTC协议的直播,这种直播方式…

一款基于Fluent设计风格、现代化的WPF UI控件库

前言 今天大姚给大家分享一款基于Fluent设计风格、开源(MIT License)、现代化的WPF UI控件库,它提供直观的设计、主题、导航和全新的沉浸式控件,全部都是原生且无缝地集成在一起:WPF UI。WPF介绍 WPF 是一个强大的桌面应用程序框架,用于构建具有丰富用户界面的 Windows 应…