题目链接

Description

lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1,10000]之间的数表示。当他使用某种装备时,他只能使用该装备的某一个属性。并且每种装备最多只能使用一次。 游戏进行到最后,lxhgww遇到了终极boss,这个终极boss很奇怪,攻击他的装备所使用的属性值必须从1开始连续递增地攻击,才能对boss产生伤害。也就是说一开始的时候,lxhgww只能使用某个属性值为1的装备攻击boss,然后只能使用某个属性值为2的装备攻击boss,然后只能使用某个属性值为3的装备攻击boss……以此类推。 现在lxhgww想知道他最多能连续攻击boss多少次?

Input

输入的第一行是一个整数N,表示lxhgww拥有N种装备 接下来N行,是对这N种装备的描述,每行2个数字,表示第i种装备的2个属性值

Output

输出一行,包括1个数字,表示lxhgww最多能连续攻击的次数。

Sample Input

3
1 2
3 2
4 5

Sample Output

2

HINT

【数据范围】

对于30%的数据,保证N < =1000

对于100%的数据,保证N < =1000000

思路

参考:

http://hzwer.com/2950.html

http://blog.csdn.net/PoPoQQQ/article/details/41544997

法一:二分图最大匹配

思路同bzoj 1911.

将每种武器和它的两种属性连边,因为属性数为\(1e3\),武器数为\(1e6\),故用属性去匹配武器,这也符合属性从小到大连续的要求。

注意点,匈牙利算法中每次都要初始化\(used[]\)数组,在这里代价太高,故可用时间戳代替(一开始将时间戳开成了\(bool\)数组玄学到哭泣)。

法二:并查集

十分巧妙。

将武器的属性抽象成点,考虑在同一种武器的两种属性间连边。

如果一个联通块了呈树形结构,且树中节点为\(x\)个,则能从中取\(x-1\)个武器。

方式是每个点分配给它上面的那条边,这样,除了根节点之外的每个点都能分配到一条边。即这些\(x-1\)个属性都能对应到一个武器。

如果不是树形结构,且其中节点为\(x\)个,则能取\(x\)个武器。

因为不是树,所以其中必然有环。那么,给环上的每个点分配它顺时针方向的一条边,给不在环上的点分配靠近环方向的边。这样,每个点都能分配到一条边。即\(x\)个属性每个都能对应到一个武器。

可以考虑用并查集来做。祖先节点为编号最大的节点,其是否可以被选择不确定,其子孙节点都是可以选择的(详见上面讨论的两种情况)。

考虑在\(x\)和\(y\)之间加边,

如果\(x\)的祖先\(fx\)与\(y\)的祖先\(fy\)相同,则说明加出了环,则祖先节点本身也可被选择;

如果不同,则让两个祖先中较小的那个未被选择的能够被选择。

最后从小到大扫描一遍,不连续即停。

小结

两种不同的建图方式,两种做法,都很有启发意义。

Code

Ver. 1

#include <bits/stdc++.h>
#define maxn 10000
#define maxm 1000010
using namespace std;
typedef long long LL;
struct Edge {
int to, ne;
Edge(int _to=0, int _ne=0) : to(_to), ne(_ne) {}
}edge[maxm * 2];
int tot, ne[maxm], T, match[maxm], vis[maxm];
void add(int u, int v) {
edge[tot] = Edge(v, ne[u]);
ne[u] = tot++;
}
int find(int u) {
for (int i = ne[u]; ~i; i = edge[i].ne) {
int v = edge[i].to;
if (vis[v] != T) {
vis[v] = T;
if (!match[v] || find(match[v])) {
match[v] = u;
return true;
}
}
}
return false;
}
int main() {
int n;
scanf("%d", &n);
tot = 0; memset(ne, -1, sizeof(ne));
for (int i = 0; i < n; ++i) {
int x, y;
scanf("%d%d", &x, &y);
add(x, i), add(y, i);
}
int i = 1;
for (; i <= maxn; ++i) {
++T;
if (!find(i)) break;
}
printf("%d\n", i-1);
return 0;
}

Ver. 2

#include <bits/stdc++.h>
#define maxn 10000
using namespace std;
typedef long long LL;
bool vis[maxn+10];
int fa[maxn+10];
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= maxn; ++i) fa[i] = i;
for (int i = 0; i < n; ++i) {
int x, y;
scanf("%d%d", &x, &y);
x = find(x), y = find(y);
if (x == y) vis[x] = true;
else {
if (x > y) swap(x, y);
if (vis[x]) vis[y] = true;
else vis[x] = true;
fa[x] = y;
}
}
int i=1;
for (; i <= maxn && vis[i]; ++i);
printf("%d\n", i-1);
return 0;
}

bzoj 1854 游戏 二分图匹配 || 并查集的更多相关文章

  1. BZOJ 1854 游戏(二分图匹配或并查集)

    此题的二分图匹配做法很容易想,就是把属性当做s集,武器当做t集,如果该武器拥有该武器则连一条边. 那么答案就是求该二分图的最大前i个匹配.将匈牙利算法改一改,当前找不到增广路就break. 但是过这个 ...

  2. HDU-3081-Marriage Match II 二分图匹配+并查集 OR 二分+最大流

    二分+最大流: 1 //题目大意:有编号为1~n的女生和1~n的男生配对 2 // 3 //首先输入m组,a,b表示编号为a的女生没有和编号为b的男生吵过架 4 // 5 //然后输入f组,c,d表示 ...

  3. BZOJ 1854: [Scoi2010]游戏(二分图匹配/并查集)

    题面: https://www.lydsy.com/JudgeOnline/problem.php?id=1854 题解: 1.二分图匹配: 首先我们发现每件装备只能在两种属性中选一种.因此,我们以每 ...

  4. [BZOJ1854][Scoi2010]游戏(二分图匹配/并查集)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1854 分析:很裸的一道二分图匹配对吧,但是在hzwer的blog上看见神奇的并查集做法 ...

  5. HDU 3081:Marriage Match II(二分图匹配+并查集)

    http://acm.hdu.edu.cn/showproblem.php?pid=3081 题意:有n个男生n个女生,他们只有没有争吵或者女生a与男生A没有争吵,且女生b与女生a是朋友,因此女生b也 ...

  6. HDU 3081 Marriage Match II (二分图,并查集)

    HDU 3081 Marriage Match II (二分图,并查集) Description Presumably, you all have known the question of stab ...

  7. BZOJ.2054.疯狂的馒头(并查集)

    BZOJ 倒序处理,就是并查集傻题了.. 并查集就是确定下一个未染色位置的,直接跳到那个位置染.然而我越想越麻烦=-= 以为有线性的做法,发现还是要并查集.. 数据随机线段树也能过去. //18400 ...

  8. noip 2010 关押罪犯 二分答案+二分图染色 || 并查集

    题目链接 题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值&q ...

  9. 2021.08.03 BZOJ 疯狂的馒头(并查集)

    2021.08.03 BZOJ 疯狂的馒头(并查集) 疯狂的馒头 - 题目 - 黑暗爆炸OJ (darkbzoj.tk) 重点: 1.并查集的神奇运用 2.离线化 题意: 给一个长为n的序列,进行m次 ...

随机推荐

  1. SonarQube安装

    要求 至少1G以上内存,推荐为2G Java:Oracle JRE 7u75+,OpenJDK 7u75+ 数据库: Microsoft SQL Server 2008/2012/2014 MySQL ...

  2. openstack中间件message queue 与memcached环境部署

    为什么要安装中间件 组件间的通信使用的是REST API 而组件内部之间的通信则是使用的中间件 首先登陆openstack的官网查看官方文档 www.openstack.org 应为在部署一个架构之前 ...

  3. hdu 2768 Cat vs. Dog (二分匹配)

    Cat vs. Dog Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  4. Socket网络编程实例2

    两个程序通过“网络”交互数据就使用socket,它只负责两件事:建立连接,传递数据. 所有的数据传输接收,必须都使用byte格式 1.简单实例: #客户端 import socket client=s ...

  5. Android SDK Manager下载,解决方案

    一.Windows 平台 在C:\Windows\System32\drivers\etc\hosts文件.添加一行:74.125.237.1       dl-ssl.google.com 二.Li ...

  6. Shell编程学习总结

    Shell编程总结 一.Hello World 新建文件test.sh 然后编辑代码: #!bin/bash/ echo “hello world !” cd 到目标目录下: chmod +x ./t ...

  7. HDOJ(HDU).1284 钱币兑换问题 (DP 完全背包)

    HDOJ(HDU).1284 钱币兑换问题 (DP 完全背包) 题意分析 裸的完全背包问题 代码总览 #include <iostream> #include <cstdio> ...

  8. YBT 5.2 树形动态规划

    题解在代码中 二叉苹果树[loj 10153] /* 若要留q条边便是要留q+1个点 所以记忆化搜索 dp[pos][ans]=max(dp[pos][ans],dp[l[pos]][k]+dp[r[ ...

  9. Linux之根文件系统的构建20160611

    说一下LINUX根文件系统的构建: 制作文件系统 1. 交叉编译busybox 安装:make install CONFIG_PREFIX=/work/nfs_root/fs_mini_mdev_ne ...

  10. c++ string写时复制

    string写时复制:将字符串str1赋值给str2后,除非str1的内容已经被改变,否则str2和str1共享内存.当str1被修改之后,stl才为str2开辟内存空间,并初始化. #include ...