2021 ICPC沈阳 H.Line Graph Matching(并查集+贪心)

题目描述

题目链接

题目大意

懒得写翻译了。

题目分析

首 先 , 本 题 要 求 的 是 图 L ( G ) 的 最 大 独 立 边 集 。 我 们 要 再 给 它 翻 译 回 图 G , L ( G ) 的 最 大 独 立 边 集 回 到 图 G 上 , 首先,本题要求的是图L(G)的最大独立边集。我们要再给它翻译回图G,L(G)的最大独立边集回到图G上, L(G)GL(G)G 即 为 : 求 G 上 相 连 的 边 对 的 集 合 的 最 大 值 。 ( 相 连 的 边 对 意 为 两 条 边 之 间 至 少 存 在 一 个 公 共 点 的 边 对 , 例 即为:求G上相连的边对的集合的最大值。(相连的边对意为两条边之间至少存在一个公共点的边对,例 G 如 : a − b , b − c ) 。 如:a-b,b-c)。 abbc

对 于 这 种 比 较 绕 的 题 目 , 我 们 可 以 先 看 看 它 有 什 么 性 质 。 对于这种比较绕的题目,我们可以先看看它有什么性质。

回 到 图 G 之 后 我 们 可 以 发 现 : 对 于 图 上 的 一 个 连 通 块 来 说 , 如 果 该 连 通 块 上 存 在 偶 数 条 边 , 那 么 我 们 可 以 选 择 回到图G之后我们可以发现:对于图上的一个连通块来说,如果该连通块上存在偶数条边,那么我们可以选择 G 该 连 通 块 上 的 所 有 边 放 入 答 案 集 中 ; 如 果 连 通 块 上 存 在 奇 数 条 边 , 那 么 我 们 只 需 要 删 除 块 上 的 某 一 条 边 , 然 后 该连通块上的所有边放入答案集中;如果连通块上存在奇数条边,那么我们只需要删除块上的某一条边,然后 将 剩 下 的 边 加 入 答 案 集 中 即 可 。 将剩下的边加入答案集中即可。

然 后 考 虑 对 于 奇 数 连 通 块 , 那 些 边 不 能 删 : 对 于 一 个 两 边 都 是 只 有 奇 数 边 连 通 块 的 桥 , 我 们 是 不 能 删 除 它 的 , 然后考虑对于奇数连通块,那些边不能删:对于一个两边都是只有奇数边连通块的桥,我们是不能删除它的, 因 为 删 除 该 边 意 味 着 会 再 多 出 两 条 无 法 进 行 匹 配 的 边 。 因为删除该边意味着会再多出两条无法进行匹配的边。

有 了 这 两 条 性 质 之 后 , 我 们 可 以 考 虑 用 并 查 集 来 维 护 每 个 连 通 块 的 联 通 性 。 有了这两条性质之后,我们可以考虑用并查集来维护每个连通块的联通性。

下 一 个 问 题 是 如 何 进 行 边 匹 配 才 能 得 到 最 大 的 收 益 。 这 里 我 们 可 以 直 接 采 用 贪 心 策 略 , 对 边 按 权 值 从 大 到 小 进 下一个问题是如何进行边匹配才能得到最大的收益。这里我们可以直接采用贪心策略,对边按权值从大到小进 行 排 序 , 每 次 将 权 值 最 大 的 边 加 入 并 查 集 中 。 行排序,每次将权值最大的边加入并查集中。

然 后 用 f [ ] 数 组 来 维 护 当 前 的 连 通 块 中 是 否 存 在 还 没 有 匹 配 的 单 边 ( 当 连 通 块 中 边 数 为 奇 数 时 , 会 出 现 一 条 无 法 然后用f[]数组来维护当前的连通块中是否存在还没有匹配的单边(当连通块中边数为奇数时,会出现一条无法 f[] 与 其 他 边 匹 配 的 单 边 ) 与其他边匹配的单边)

一 、 每 次 将 边 加 入 到 并 查 集 中 时 , 如 果 该 边 的 两 点 u , v 都 在 同 一 块 并 查 集 中 , 则 说 明 该 边 在 这 个 连 通 块 中 。 一、每次将边加入到并查集中时,如果该边的两点u,v都在同一块并查集中,则说明该边在这个连通块中。 uv 如 果 f [ r o o t ] 存 在 , 那 么 该 边 就 与 f [ r o o t ] 进 行 匹 配 , 匹 配 完 成 后 清 空 f [ r o o t ] 。 如果f[root]存在,那么该边就与f[root]进行匹配,匹配完成后清空f[root]。 f[root]f[root]f[root]

二 、 如 果 该 边 的 两 点 u , v 不 在 同 一 并 查 集 中 , 则 要 对 这 两 个 并 查 集 进 行 合 并 。 这 里 有 三 种 情 况 : 二、如果该边的两点u,v不在同一并查集中,则要对这两个并查集进行合并。这里有三种情况: uv

1 、 f [ r o o t ( u ) ] 和 f [ r o o t ( v ) ] 都 不 存 在 , 那 么 两 树 合 并 后 , f [ r o o t ] 即 为 这 条 新 边 即 可 。 1、f[root(u)]和f[root(v)]都不存在,那么两树合并后,f[root]即为这条新边即可。 1f[root(u)]f[root(v)]f[root]

2 、 f [ r o o t ( u ) ] 和 f [ r o o t ( v ) ] 两 个 中 只 存 在 一 个 , 那 么 两 树 合 并 后 , 新 放 入 的 边 和 其 中 存 在 的 f [ r o o t ] 和 并 即 可 。 2、f[root(u)]和f[root(v)]两个中只存在一个,那么两树合并后,新放入的边和其中存在的f[root]和并即可。 2f[root(u)]f[root(v)]f[root]

3 、 f [ r o o t ( u ) ] 和 f [ r o o t ( v ) ] 都 存 在 , 那 么 说 明 u 和 v 所 在 的 连 通 块 都 为 奇 数 边 , u − v 边 即 为 两 连 通 块 的 桥 。 因 此 该 边 3、f[root(u)]和f[root(v)]都存在,那么说明u和v所在的连通块都为奇数边,u-v边即为两连通块的桥。因此该边 3f[root(u)]f[root(v)]uvuv 我 们 是 不 能 删 除 它 的 , 所 以 我 们 要 让 u − v 边 与 f [ r o o t ( u ) ] 和 f [ r o o t ( v ) ] 中 的 最 大 值 匹 配 , 新 连 通 块 剩 下 的 边 为 我们是不能删除它的,所以我们要让u-v边与f[root(u)]和f[root(v)]中的最大值匹配,新连通块剩下的边为 uvf[root(u)]f[root(v)] f [ r o o t ( u ) ] 和 f [ r o o t ( v ) ] 的 最 小 值 即 可 。 f[root(u)]和f[root(v)]的最小值即可。 f[root(u)]f[root(v)]

不愧是银牌题,得写这么多。。。。

代码如下
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <algorithm>
#include <iomanip>
#define LL long long
#define ULL unsigned long long
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define PDD pair<double,double>
#define x first
#define y second
using namespace std;
const int N=2e5+5,mod=1e9+7;
struct Edge{				//记录边的结构体
	int u,v,w;
	bool operator<(const Edge &a) const
	{ return w>a.w; }
}e[N];
int p[N],f[N];			//p[]记录并查集点,f[]记录连通块中剩下的那条边的边权
int find(int x)			//并查集模板
{
	if(p[x]!=x) p[x]=find(p[x]);
	return p[x];
}
int main()
{
	cin.tie(0);
	ios::sync_with_stdio(false);
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) p[i]=i,f[i]=0;		//初始化
	for(int i=1;i<=m;i++)
	{
		int u,v,w;
		cin>>u>>v>>w;
		e[i]={u,v,w};
	}
	sort(e+1,e+1+m);				//按边权从大到小排序(贪心)
	LL ans=0;
	for(int i=1;i<=m;i++)
	{
		int u=find(e[i].u),v=find(e[i].v),w=e[i].w;
		if(u==v)			//情况1
		{
			if(!f[u]) f[u]=w;
			else ans+=w+f[u],f[u]=0;
		}
		else 
		{
			p[v]=u;
			if(!f[u]&&!f[v]) f[u]=w;						//情况2.1
			else if(!f[u]||!f[v]) ans+=w+f[u]+f[v],f[u]=0;	//情况2.2
			else ans+=w+max(f[u],f[v]),f[u]=min(f[u],f[v]);	//情况2.3
		}
	}
	cout<<ans<<endl;
	return 0;
}
  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lwz_159

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值