/*
<1>要求:这道题的要求是给定一个无向联通图,判断这个图的最小生成树MST是不是唯一的,如果是唯一的则
打印出最小值,如果不是唯一的给出提示
<2>分析:采用Kruskal算法来计算最小生成树,仔细分析其过程不难发现这个图的MST不唯一的充分必要条件是
在Kruskal运算过程中如果选中的当前边a构成了环,且在所有包含这条边的环中如果存在和这条边权值相等的
边b,则MST不唯一,因为总是可以利用a取代b构成一个新的MST.算法清楚了, 那么实现最难的地方就是找环了
<3>实现:为了提高计算的速度,我将边保存两份,一份用结构表示,存储所有边,用来排序和MST遍历边用;
另外一份用邻接表表示有提高计算环时候的处理速度,数据结构确定了那么很容易利用DFS回溯,在DFS回溯的
过程中判断环以及是否有和目标边权值相等的边,判断环没有用并查集而是直接在DFS中判断
6085976 bobten2008 1679 Accepted 256K 0MS C++ 2201B 2009-11-03 20:42:08
*/
#include <iostream>
#include <algorithm>
#define MAX_E 5010
#define MAX_N 105
using namespace std;
//MST算法中用来表示当前节点是否被访问过
bool v[MAX_N + 1];
//存储所有边
struct edge
{
int from, to, w;
}edges[MAX_E + 1];
//节点数以及边数
int noden, edgen;
//边的邻接表存储
struct head
{
int from, to, w;
head *next;
}*heads[MAX_N + 1];
//对边按照权值升序排列的比较函数
bool compare(const edge &e1, const edge &e2)
{
return e1.w <= e2.w;
}
//初始化
void init()
{
int i;
for(i = 1; i <= noden; i++)
{
heads[i] = NULL;
v[i] = false;
}
}
//往邻接表中插入边
void insertEdge(int from, int to, int w)
{
head *temp = new head();
temp->from = from; temp->to = to; temp->w = w;
temp->next = heads[from];
heads[from] = temp;
}
//dfs算法判断换需要的相关参数,dfsDest表示目标结点,dfsW表示目标边的权值
int dfsDest, dfsW;
//ununique用来表示MST是否唯一
bool ununique;
//dfs算法中用来比较当前节点是否被访问过
bool dfsv[MAX_N + 1];
//返回值为true表示从curNode往后可以遍历到dfsDest,即构成一条环
bool dfsCheckCycle(int curNode)
{
//减枝,如果已经发现MST不唯一则退出
if(ununique) return true;
//到达目标节点,即发现环
if(curNode == dfsDest) return true;
bool returnval = false;
//当前节点如果没有被访问过
if(!dfsv[curNode])
{
//访问当前节点
dfsv[curNode] = true;
//访问当前节点的所有邻居
head *temp = heads[curNode];
while(temp)
{
bool cur;
//如果从邻居temp->to可以形成环,且这条边的权值等于dfsW,则预示着MST不唯一
if((cur = dfsCheckCycle(temp->to)) && temp->w == dfsW)
{
ununique = true;
return true;
}
temp = temp->next;
returnval |= cur;
}
dfsv[curNode] = false;
return returnval;
}
else return false;
}
//MST算法
int getMST()
{
int countv = 0, pos = 0, total = 0;
while(countv < noden && pos < edgen)
{
int from = edges[pos].from, to = edges[pos].to, w = edges[pos].w;
//cycle
if(v[from] && v[to])
{
memset(dfsv, 0, sizeof(dfsv));
dfsDest = to;
dfsW = w;
ununique = false;
//寻找是否存在环中权值与w相同的其他边
bool haveCircle = dfsCheckCycle(from);
if(ununique) return -1;
if(haveCircle) { //有环布插入边
pos++;
continue;
}
}
//无欢插入边
v[from] = v[to] = true;
total += w;
insertEdge(from, to, w);
insertEdge(to, from, w);
pos++;
}
return total;
}
int main()
{
int caseNum, i;
scanf("%d", &caseNum);
while(caseNum--)
{
scanf("%d%d", &noden, &edgen);
init();
int from, to, w;
for(i = 0; i < edgen; i++)
{
scanf("%d%d%d", &from, &to, &w);
edges[i].from = from;
edges[i].to = to;
edges[i].w = w;
//insertEdge(from, to, w); insertEdge(to, from, w);
}
sort(edges, edges + edgen, compare);
int res = getMST();
if(res == -1) printf("Not Unique!/n");
else printf("%d/n", res);
}
return 0;
}