题意:有n个点 、 给出m条边 , 判断这个图的次小生成树是否唯一?
判断一个次小生成树是否唯一: 首先由kruskal算法求出最小生成树 , 并且记录生成树上 , 任意两点路径上的最大边权 , 然后再把不属于最小生成树的边 , 一条一条加入生成树、再删除该条路径权值最大的边 , 然后再判断新得到的生成树的权值是否和最小生成树的权值一样、
代码:
在代码中 , 我们用数组模拟了链表 , 这个链表是用来存储每一次被生成树加入的点 , 并且不连通的点不属于一个链表 。
#include
#include
#include
#include
using namespace std;
#define maxn 1000000
int n , m;
int p[110];
int rank[110];
int dist[110][110];
struct node
{
int u , v;
int w;
bool select ;
}grap[10000];
struct xt
{
int to;
int next;
}xy[110];
int head[110] , end[110]; //分别表示链表的头指针位置和尾指针位置
bool cmp(node xx , node yy)
{
return xx.w <= yy.w;
}
void init()
{
memset(head , -1 , sizeof(head));
memset(rank , 0 , sizeof(rank));
for(int i = 1; i <= n; i++)
p[i] = i;
}
int find(int x)
{
int g = x , h;
while(x != p[x])
x = p[x];
while(p[g] != x)
{
h = p[g];
p[g] = x;
g = h;
}
return x;
}
int inline min(int x ,int y)
{
if(x < y)
return x;
return y;
}
int kruskal()
{
int i , k = 0 , x , y ;
int sum = 0;
for(i = 0; i < n; i++)//这里是在用数组模拟链表
{
xy[i].to = i+1;
xy[i].next = head[i+1];
end[i+1] = i;
head[i+1] = i;
}
//初始化时 ,每个点只有自己 , 也就是说 , 每个点都是一颗独立的树
for(i = 0; i < m; i++)
{
x = find(grap[i].u) , y = find(grap[i].v);
if(x != y)
{
for(int w = head[x] ; w != -1; w = xy[w].next) //把课树上所有的点都存起来,
for(int v = head[y] ; v != -1 ; v = xy[v].next)
dist[xy[w].to][xy[v].to] = dist[xy[v].to][xy[w].to] = grap[i].w;
//对于这个找每个路径上的最大值 , 为什么不会重复? 因为找的是两个点的路径 , 并且前提条件是这两个点不在同一颗树上(也就是根节点不一样) ,
//而 , 在这次找个之后 , 有把这两树合并成一颗树, 所每个点之间只会碰到一次 ,
xy[end[y]].next = head[x];
end[y] = end[x];
p[x] = y;
k++;
grap[i].select = true;
sum += grap[i].w;
}
//else grap[i].select = false;
if(k >= n-1)
break;
}
return sum;
}
int main()
{
int t;
cin>>t;
while(t--)
{
scanf("%d %d" , &n , &m);
init();
int i ;
for(i = 0; i < m; i++)
{
scanf("%d %d %d" , &grap[i].u , &grap[i].v , &grap[i].w);
grap[i].select = false;
}
sort(grap , grap+m , cmp);
int sum = kruskal();
int xx = 100000;
for(i = 0; i < m; i++)
{
if(!grap[i].select)
{
xx = min(xx , sum + grap[i].w - dist[grap[i].u][grap[i].v]);
}
}
//
cout<<sum<<","<<xx<<endl;
if(xx != sum)
cout<<sum<<endl;
else
cout<<"Not Unique!"<<endl;
}
return 0;
}
判断一个次小生成树是否唯一: 首先由kruskal算法求出最小生成树 , 并且记录生成树上 , 任意两点路径上的最大边权 , 然后再把不属于最小生成树的边 , 一条一条加入生成树、再删除该条路径权值最大的边 , 然后再判断新得到的生成树的权值是否和最小生成树的权值一样、
代码:
在代码中 , 我们用数组模拟了链表 , 这个链表是用来存储每一次被生成树加入的点 , 并且不连通的点不属于一个链表 。
#include
#include
#include
#include
using namespace std;
#define maxn 1000000
int
int p[110];
int rank[110];
int dist[110][110];
struct node
{
}grap[10000];
struct xt
{
}xy[110];
int head[110] , end[110]; //分别表示链表的头指针位置和尾指针位置
bool cmp(node xx , node yy)
{
}
void init()
{
}
int find(int x)
{
}
int inline min(int x ,int y)
{
}
int kruskal()
{
//初始化时 ,每个点只有自己 , 也就是说 , 每个点都是一颗独立的树
//对于这个找每个路径上的最大值 , 为什么不会重复? 因为找的是两个点的路径 , 并且前提条件是这两个点不在同一颗树上(也就是根节点不一样) ,
//而 , 在这次找个之后 , 有把这两树合并成一颗树, 所每个点之间只会碰到一次 ,
}
int main()
{
}