poj 2485 简单的最小生…

本文探讨了如何求解生成树中边权最大值最小的问题,通过改进Kruskal算法并利用并查集确保生成树的正确构建。文章详细解释了算法流程及核心代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目意思:要你求一个生成树 , 使这个生成树(不一定是最小生成树)中边权最大值最小 , 并输出该值。

这个题目我一开始用的是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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值