题目描述:给定一个无向图,要求判断该图的最小生成树是否唯一,如果唯一的话输出最小生成树的权值,如果不唯一,输出Not Unique!
解题思路:要判断最小生成树是否唯一,可以求出次小生成树,看权值是否和最小生成树相等,如果相等的话说明最小生成树不唯一,否则说明最小生成树是唯一的,那么,只要求出次小生成树来就好办了。我用的是Kruskal算法求出最小生成树来,然后依次枚举这些树边并去掉,再求最小生成树,所得的这些值的最小值就是次小生成树的值,当然,前提是去掉一条树边以后,剩下的边可以形成次小生成树。
ps:这题糊里糊涂就过了,不知道是不是数据太弱,我总感觉自己考虑不周全,却不知道在哪里……
解题思路:要判断最小生成树是否唯一,可以求出次小生成树,看权值是否和最小生成树相等,如果相等的话说明最小生成树不唯一,否则说明最小生成树是唯一的,那么,只要求出次小生成树来就好办了。我用的是Kruskal算法求出最小生成树来,然后依次枚举这些树边并去掉,再求最小生成树,所得的这些值的最小值就是次小生成树的值,当然,前提是去掉一条树边以后,剩下的边可以形成次小生成树。
ps:这题糊里糊涂就过了,不知道是不是数据太弱,我总感觉自己考虑不周全,却不知道在哪里……
#include
<
iostream
>
#include < algorithm >
using namespace std;
int n,m,cas;
struct node
{
int u,v,w;
}edge[ 10000 ];
int sum,num;
int mst,smst = 0x7fffffff ; // mst----最小生成树权值smst----次小生成树权值
bool v[ 10000 ],can[ 10001 ]; // v记录是不是最小生成树的树边,can记录能否在求次小生成树时用到某边
int p[ 10001 ],rank[ 10001 ];
int Makeset()
{
int i;
for (i = 1 ;i <= n;i ++ )
{
p[i] = i;
rank[i] = 0 ;
}
return 0 ;
}
int Find( int t)
{
if (t != p[t])
{
p[t] = Find(p[t]);
}
return p[t];
}
bool cmp(node a,node b)
{
return a.w < b.w;
}
int Union( int a, int b)
{
int x = Find(a);
int y = Find(b);
if (rank[x] > rank[y])
{
p[y] = x;
}
else
{
p[x] = y;
if (rank[x] == rank[y])
{
rank[y] ++ ;
}
}
return 0 ;
}
int Kruskal()
{
num = 0 ;
sum = 0 ;
Makeset();
int i;
for (i = 0 ;i < m;i ++ )
{
if (Find(edge[i].u) != Find(edge[i].v))
{
Union(edge[i].u,edge[i].v);
sum += edge[i].w;
v[i] = 1 ;
num ++ ;
}
if (num == n - 1 )
break ;
}
return sum;
}
int Sec_Kruskal()
{
num = 0 ;
sum = 0 ;
int i;
Makeset();
for (i = 0 ;i < m;i ++ )
{
if (can[i])
{
if (Find(edge[i].u) != Find(edge[i].v))
{
Union(edge[i].u,edge[i].v);
sum += edge[i].w;
num ++ ;
}
if (num == n - 1 )
break ;
}
}
return sum;
}
int main()
{
int i,j;
scanf( " %d " , & cas);
while (cas -- )
{
smst = 0x7fffffff ;
scanf( " %d%d " , & n, & m);
for (i = 0 ;i < m;i ++ )
{
scanf( " %d%d%d " , & edge[i].u, & edge[i].v, & edge[i].w);
}
memset(can, 1 , sizeof (can));
memset(v, 0 , sizeof (v));
sort(edge,edge + m,cmp);
mst = Kruskal();
for (i = 0 ;i < m;i ++ )
{
if (v[i])
{
can[i] = 0 ;
int tmp = Sec_Kruskal();
if (tmp >= mst && smst > tmp) // 如果tmp<mst说明不能形成次小生成树
{
smst = tmp;
}
can[i] = 1 ;
}
}
if (mst == smst && smst != 0 )
{
printf( " Not Unique!\n " );
}
else
{
printf( " %d\n " ,mst);
}
// printf("%d %d\n",mst,smst);
}
// system("pause");
return 0 ;
}
#include < algorithm >
using namespace std;
int n,m,cas;
struct node
{
int u,v,w;
}edge[ 10000 ];
int sum,num;
int mst,smst = 0x7fffffff ; // mst----最小生成树权值smst----次小生成树权值
bool v[ 10000 ],can[ 10001 ]; // v记录是不是最小生成树的树边,can记录能否在求次小生成树时用到某边
int p[ 10001 ],rank[ 10001 ];
int Makeset()
{
int i;
for (i = 1 ;i <= n;i ++ )
{
p[i] = i;
rank[i] = 0 ;
}
return 0 ;
}
int Find( int t)
{
if (t != p[t])
{
p[t] = Find(p[t]);
}
return p[t];
}
bool cmp(node a,node b)
{
return a.w < b.w;
}
int Union( int a, int b)
{
int x = Find(a);
int y = Find(b);
if (rank[x] > rank[y])
{
p[y] = x;
}
else
{
p[x] = y;
if (rank[x] == rank[y])
{
rank[y] ++ ;
}
}
return 0 ;
}
int Kruskal()
{
num = 0 ;
sum = 0 ;
Makeset();
int i;
for (i = 0 ;i < m;i ++ )
{
if (Find(edge[i].u) != Find(edge[i].v))
{
Union(edge[i].u,edge[i].v);
sum += edge[i].w;
v[i] = 1 ;
num ++ ;
}
if (num == n - 1 )
break ;
}
return sum;
}
int Sec_Kruskal()
{
num = 0 ;
sum = 0 ;
int i;
Makeset();
for (i = 0 ;i < m;i ++ )
{
if (can[i])
{
if (Find(edge[i].u) != Find(edge[i].v))
{
Union(edge[i].u,edge[i].v);
sum += edge[i].w;
num ++ ;
}
if (num == n - 1 )
break ;
}
}
return sum;
}
int main()
{
int i,j;
scanf( " %d " , & cas);
while (cas -- )
{
smst = 0x7fffffff ;
scanf( " %d%d " , & n, & m);
for (i = 0 ;i < m;i ++ )
{
scanf( " %d%d%d " , & edge[i].u, & edge[i].v, & edge[i].w);
}
memset(can, 1 , sizeof (can));
memset(v, 0 , sizeof (v));
sort(edge,edge + m,cmp);
mst = Kruskal();
for (i = 0 ;i < m;i ++ )
{
if (v[i])
{
can[i] = 0 ;
int tmp = Sec_Kruskal();
if (tmp >= mst && smst > tmp) // 如果tmp<mst说明不能形成次小生成树
{
smst = tmp;
}
can[i] = 1 ;
}
}
if (mst == smst && smst != 0 )
{
printf( " Not Unique!\n " );
}
else
{
printf( " %d\n " ,mst);
}
// printf("%d %d\n",mst,smst);
}
// system("pause");
return 0 ;
}