题目链接: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;
} */
}
感觉有帮助的话,点个赞再走吧!