牛客算法周周练17 A题 - 生成树 C++

题目链接:https://ac.nowcoder.com/acm/contest/6607/A

Description

你有一张n个点的完全图(即任意两点之间都有无向边)
现在给出这张图的两棵生成树
定义一次操作为:在任意一棵生成树中删除一条边后再加入一条边(必须在同一棵树中操作),同时需要保证操作完后仍然是一棵树
问使得两棵树相同的最少操作次数,若不存在合法的操作方案,输出-1

注意:这里的相同指的是点集与边集均相同,也就是对于第一棵树中的边(u, v),第二棵树中一定存在边(u, v)或(v, u),再不懂请看样例解释。

Input

一个整数n表示无向图的点数 (2⩽n⩽105 保证输入数据合法)
接下来n - 1行,每行两个整数u, v表示第一棵生成树中的边
再接下来n - 1行,每行两个整数u, v表示第二棵生成树中的边

Output

一个整数,表示最少操作次数

Sample Input
6
6 1
1 2
2 3
3 5
5 4
1 2
2 4
4 5
5 3
6 4
Sample Output
2
Explanation

题目中的树如下所示
在这里插入图片描述

一种方案如下:
第二棵树中删除(2, 4),增加(2,3)
第二棵树中删除(4, 6),增加(1, 6)
注意:如果仅在第二棵树中删除(2, 4),增加(1, 6),得到的树虽然形态相同,但是边集不同,我们不认为它们是相同的!

Solution

基础知识:
连通图中的生成树必须满足以下 2 个条件:
1、包含连通图中所有的顶点;
2、任意两顶点之间有且仅有一条通路;
因此,连通图的生成树具有这样的特征,即生成树中边的数量 = 顶点数 - 1。

完全图是连通图,所以给出的生成树满足以上条件。那么显然我们要求的就是给出的两棵生成树中不同的边的条数。简而言之,就是去一下重。利用一下set,然后因为一条边连接两个顶点,所以需要重载一下 < 运算符。

Code
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
struct node {
    int x, y;
    bool operator<(const node& a) const {//不是内置类型,需要重载
        if (x != a.x) return x < a.x;
        else return y < a.y;
    }
};
int main() {
    set<node> v;
    int n;
    cin >> n;
    int xx,yy;
    for (int i = 0; i < n - 1; i++) {
        cin >> xx >> yy;
        if (xx > yy) swap(xx, yy);
        v.insert(node{xx,yy});
    }
    /*for (auto i : v) {//可以输出观察一下
        cout << i.x << " "<<i.y<< endl;
    } */
    int ans = v.size();
    for (int i = 0; i < n - 1; i++) {
        cin >> xx >> yy;
        if (xx > yy) swap(xx, yy);
        v.insert(node{xx,yy});
    }
    cout << v.size() - ans << endl;
    /*for (auto i : v) {//可以输出观察一下
        cout << i.x << " "<<i.y<< endl;
    } */
}

感觉有帮助的话,点个赞再走吧!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值