poj 1679 TheUniqueMST 最小生成樹Kruskal(、Prim待做

題意:
給定連接的無向圖,告訴它的最小生成樹是否唯一。
定義1(生成樹):考慮連通的無向圖G =(V,E)。G的生成樹是G的子圖,比如T =(V’,E’),具有以下屬性:
1.V’= V.
2.T是連通的和非循環的。
定義2(最小生成樹):考慮邊加權,連通,無向圖G =(V,E)。G的最小生成樹T =(V,E’)是總成本最小的生成樹。T的總成本是指E’中所有邊緣的權重之和。

Input:
第一行包含單個整數t(1 <= t <= 20),即測試用例的數量。每個案例代表一個圖表。它以包含兩個整數n和m(1 <= n <= 100),節點數和邊數的行開始。以下m行中的每一行包含三元組(xi,yi,wi),表示xi和yi通過權重= wi的邊連接。對於任何兩個節點,最多隻有一個邊連接它們。

Output:
對於每個輸入,如果MST是唯一的,則打印它的總成本,否則打印字符串’Not Unique!’。

思路:

  • Kruskal求最小生成樹的值+記錄邊
  • 對每條邊,判斷去掉這條邊後是否能夠構成值相同的最小生成樹

參考:

  • Kruskal:
    https://blog.csdn.net/Albert_Bolt/article/details/82253141
    https://www.iteye.com/blog/hefeijack-1901181
  • Prim:
    好的代碼及思路講解
    https://www.cnblogs.com/kuangbin/p/3147329.html

Kruskal:

#pragma warning(disable:4996)
#include<iostream>
#include<string>
#include<cmath>
#include<ctype.h>
#include<memory.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<iomanip>
#include<set>
#include<list>
#include<vector>
#include<stack>
#include<queue>
#define ll long long int
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 110;

struct EDGE
{
	int u, v, w;
};
bool cmp(EDGE a, EDGE b)
{
	return a.w < b.w;
}

int n, m;
EDGE edge[maxn * maxn];
int par[maxn];
int path[maxn];

int find(int x)
{
	if (par[x] == x)
		return par[x];
	return par[x] = find(par[x]);
}

void initialize()
{
	for (int i = 0; i <= n; i++)//要有=啊!不然就錯了,所以以後直接i<maxn,乾脆全部初始化了算了
		par[i] = i;
}


int main()
{
	int T; cin >> T;
	while (T--)
	{
		cin >> n >> m;
		for (int i = 0; i < m; i++)
			cin >> edge[i].u >> edge[i].v >> edge[i].w;
		initialize();

		sort(edge, edge + m, cmp);

		int cnt = 0;//記錄路徑時候用
		int ans = 0;//保存最小生成樹的結果
		for (int i = 0; i < m; i++)
		{
			int fa = find(edge[i].u);
			int fb = find(edge[i].v);
			if (fa != fb)
			{
				par[fb] = fa;
				ans += edge[i].w;
				path[cnt++] = i;
			}
		}

		int flag = 1;
		//去掉已經得到的最小生成樹的每一條邊,再次計算最小生成樹,
		//隨後求值,如果刪除一條之後,所得值和之前相等,則說明最小生成樹不唯一
		for (int ii = 0; ii < cnt; ii++)
		{
			initialize();

			int sum = 0;//用來求後來的最小生成樹的值
			int edge_cnt = 0;//判斷能否構成最小生成樹

			for (int i = 0; i < m; i++)
			{
				if (i == path[ii])continue;//如果是要刪去的這條邊,則跳過
				
				int fa = find(edge[i].u);
				int fb = find(edge[i].v);
				if (fa != fb)
				{
					par[fb] = fa;
					sum += edge[i].w;
					edge_cnt++;
				}
			}
			//cout << sum << " ";
			if (edge_cnt == n - 1 && sum == ans)
			{
				//cout << "Not Unique!" << endl;
				flag = 0;
				//break;
			}
		}
		
		if (flag)
			::cout << ans << endl;
		else
			::cout << "Not Unique!" << endl;

	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章