题目意思:要你求一个生成树 , 使这个生成树(不一定是最小生成树)中边权最大值最小 , 并输出该值。
这个题目我一开始用的是kruskal算法 , 先对边进行排序 , 但后面犯了一个错误 , 当判断是否存在生成树时 , 我判断的是前面的边是否包含所有顶点(没有发现 , 有可能这些点不是在通一个连通图中) , 应该用并查集 。
其实最大值最小就是最小生成树中的最大值 , 这个性质的证明可以用kruskal算法来证明:
1、对边排序后 , 我们取前n-1条边 , 如果这n-1条边 , 构成了最小生成树 ,
那么该值就是它们之间的最大值 。
2、如果不能构成生成树 , 那么继续加入下一条边(除开已取的边之外 , 取剩下边的最小值) ,
因为前面那些边不能构成生成树 , 那么如果加入这条边之后 , 可以构成生成树 , 则这条边肯定在该生成树中 ,
并且这条边的权值就是我们要求的值 。
3、如果加入该边后还不能构成最小生成树 , 那么重复步骤2
, 直到可以形成生成树为止。
代码:
#include
#include
#include
using namespace std;
const int MAXN = 550 ;
int grap[MAXN][MAXN] , u[630000] , v[630000] , d[630000] ;
int done[630000] , n , f[MAXN];
bool cmp(int i , int j)
{
return d[i]
< d[j];
}
int find(int x)
{
int u =
x;
while(x !=
f[x])
{
x =
f[x];
}
while(u !=
x)
{
int p =
f[u];
f[u] =
x;
u = p;
}
return
x;
}
int main()
{
int t;
scanf("%d" ,
&t);
while(t--)
{
int i ,
j;
cin>>n;
for(i = 1; i
<= n; i++)
{
for(j = 1; j
<= n; j++)
scanf("%d" ,
&grap[i][j]);
f[i] =
i;
}
int x =
0;
for(i = 1; i
<= n; i++)
{
for(j = i+1;
j <= n; j++)
{
u[x] =
i; v[x] = j;
d[x] =
grap[i][j];
done[x] =
x;
x +=
1;
}
}
int c , g ,
h;
sort(done ,
done+x , cmp);
for(i = 0 ;
i < n-2; i++)
{
c =
done[i];
g =
find(u[c]) ; h = find(v[c]);
if(g !=
h) f[g] = h;
}
for(i = n-2
; i < x; i++)
{
c =
done[i];
g =
find(u[c]); h = find(v[c]);
if(g !=
h) f[g] = h;
int sum =
0;
for(j = 1; j
<= n; j++)
if(f[j] ==
j) sum += 1;
if(sum
< 2) break;
}
x =
done[i];
cout<<d[x]<<endl;
}
return
0;
}
这个题目我一开始用的是kruskal算法 , 先对边进行排序 , 但后面犯了一个错误 , 当判断是否存在生成树时 , 我判断的是前面的边是否包含所有顶点(没有发现 , 有可能这些点不是在通一个连通图中) , 应该用并查集 。
其实最大值最小就是最小生成树中的最大值 , 这个性质的证明可以用kruskal算法来证明:
代码:
#include
#include
#include
using namespace std;
const int MAXN = 550 ;
int grap[MAXN][MAXN] , u[630000] , v[630000] , d[630000] ;
int done[630000] , n , f[MAXN];
bool cmp(int i , int j)
{
}
int find(int x)
{
}
int main()
{
}