LeetCode 1579. 保证图可完全遍历

题目链接:LeetCode 1579. 保证图可完全遍历

题意:

   Alice 和 Bob 共有一个无向图,其中包含 n 个节点和 3  种类型的边:

  • 类型 1:只能由 Alice 遍历。
  • 类型 2:只能由 Bob 遍历。
  • 类型 3:Alice 和 Bob 都可以遍历。

给你一个数组 edges ,其中 edges[i] = [typei, ui, vi] 表示节点 ui 和 vi 之间存在类型为 typei 的双向边。请你在保证图仍能够被 Alice和 Bob 完全遍历的前提下,找出可以删除的最大边数。如果从任何节点开始,Alice 和 Bob 都可以到达所有其他节点,则认为图是可以完全遍历的。

返回可以删除的最大边数,如果 Alice 和 Bob 无法完全遍历图,则返回 -1

输入:n = 4, edges = [[3,1,2],[3,2,3],[1,1,3],[1,2,4],[1,1,2],[2,3,4]]
输出:2
解释:如果删除 [1,1,2] 和 [1,1,3] 这两条边,Alice 和 Bob 仍然可以完全遍历这个图。再删除任何其他的边都无法保证图可以完全遍历。所以可以删除的最大边数是 2 。

 

解题思路:

   变种的最小生成树(克鲁斯卡尔算法),贪心可得优先选择类型3的边,因为类型3的边Alice和Bob都可以访问,然后再选择类型1或类型2,查看最后两个两个连通块是否大于1,如果大于1,不满足

class Solution {
public:
	vector<int> pa, pb;
	int get(vector<int>& p, int x) { // 路径压缩进行查找
		if(p[x] != x) { 
			p[x] = get(p, p[x]);
		}
		return p[x];
	}
    int maxNumEdgesToRemove(int n, vector<vector<int>>& edges) {
    	pa.resize(n+1), pb.resize(n+1);
    	for(int i = 1; i <= n; i++) { // 初始化两个连通块
    		pa[i] = pb[i] = i;
    	}
    	int res = 0, ca = n, cb = n;
    	for(auto&e: edges) {
    		if(e[0] == 3) {  // 优先选择 类型3
    			int x = e[1], y = e[2];
    			int pax = get(pa, x), pay = get(pa, y);  此时,Alice和Bob都可以通过
    			int pbx = get(pb, x), pby = get(pb, y);
    			if(pax != pay) {
    				pa[pax] = pay; ca--;
    				pb[pbx] = pby; cb--;
    			} else {
    				res++;  // 如果相等,说明两点已经联通,多出一条边
    			}
    		}
    	}
    	for(auto &e: edges) {
    		int t = e[0], x = e[1], y = e[2];
    		if(t == 1) {
    			int pax = get(pa, x), pay = get(pa, y);
    			if(pax != pay) {
    				pa[pax] = pay; ca--;
    			} else {
    				res++;
    			}
    		} else if(t == 2){
    			int pbx = get(pb, x), pby = get(pb, y);
    			if(pbx != pby) {
    				pb[pbx] = pby; cb--;
    			} else {
    				res++;
    			}
    		}
    	}
    	if(ca > 1 || cb > 1) {
    		return -1;
    	} else {
    		return res;
    	}
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值