1. 程式人生 > >生成樹(光棍 牛客, 思維)

生成樹(光棍 牛客, 思維)

連結: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;
}