生成树(光棍 牛客, 思维)

链接:https://ac.nowcoder.com/acm/contest/223/A
来源:牛客网
 

题目描述

你有一张n个点的完全图(即任意两点之间都有无向边)
现在给出这张图的两棵生成树
定义一次操作为:在任意一棵生成树中删除一条边后再加入一条边(必须在同一棵树中操作),同时需要保证操作完后仍然是一棵树

问使得两棵树相同的最少操作次数,若不存在合法的操作方案,输出-1

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

输入描述:

一个整数n表示无向图的点数
接下来n - 1行,每行两个整数u, v表示第一棵生成树中的边
再接下来n - 1行,每行两个整数u, v表示第二棵生成树中的边

输出描述:

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

示例1

输入

复制

6
6 1
1 2
2 3
3 5
5 4
1 2
2 4
4 5
5 3
6 4

输出

复制

2

说明

 

题目中的树如下所示

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

示例2

输入

复制

3
1 2
2 3
1 3
3 2

输出

复制

1

示例3

输入

复制

2
1 2
2 1

输出

复制

0

备注:

 

保证输入数据合法

思维题:刚开始没有想到,想到好几种办法,但到最后都被自己推翻了。

二维数组太大,所以降成了一维数组,但却有个问题,用一维数组存边时,会出现重复问题,导致边被覆盖,那么,又该如何解决这一问题呢???

对于一颗生成树来说,一个点最多才能够连接两条边因此可以将一条边正着存,一条边反着存。

例如:1       2

           1       3

        就可以这样存:dp[1] = 2; dp[3] = 1;

问题就会迎刃而解:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>

using namespace std;

const int maxn = 1e5+5;
int t1[maxn];

int main()
{
	int n;
	scanf("%d", &n);
	memset(t1, 0, sizeof(t1));
	for(int i = 0; i < n-1; i++){
		int a, b;
		scanf("%d%d", &a, &b);
		if(!t1[a]) t1[a] = b;
		else t1[b] = a;
	}
	
	int cnt = 0;
	for(int i = 0; i < n-1; i++){
		int a, b;
		scanf("%d%d", &a, &b);
		if(t1[a] == b||t1[b] == a) cnt++;
	}
	
	printf("%d\n", n-1-cnt);
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_41818544/article/details/83627171