hdu 1863 最小生成树

http://acm.hdu.edu.cn/showproblem.php?pid=1863

还是最小生成树,还是用了kruskal写,就是有点不一样的地方在于,他要让你判断是否能够保证畅通,也就是是否能有最小生成树,其实就是判断是不是连通图吧,因为连通图一定会有最小生成树。

一开始我的想法是,先进行一次并查集的合并与查找,看一下有几个集合,如果只有一个集合的话就是连通图,肯定有最小生成树存在,如果多余一个集合就不会有,直接输出问好。之后要记得还原根节点。。

附上代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 1000000
int u[M],v[M],p[M],w[M];
int r[M],t[M];
int n,m;
int ans;
int cmp(int a,int b)
{
    return w[a] < w[b];
}
int find(int x)
{
    return p[x]==x?x:p[x]=find(p[x]);
}
void uni(int x,int y)
{
    if(x!=y)
        p[x] = y;
}
int kruskal()
{
    for(int i = 0;i < n;i++)
    {
        int e = r[i];
        int x = find(u[e]),y = find(v[e]);
        if(x!=y)
        {
            p[x] = y;
            ans += w[e];
        }
    }
}
int main()
{
    while(scanf("%d %d",&n,&m)==2 && n)
    {
        memset(t,0,sizeof(t));
        ans = 0;
        int num = 0;
        for(int i = 1;i <= m;i++) p[i] = i;
        for(int i = 0;i < n;i++) r[i] = i;
        for(int i = 0;i < n;i++)
        {
            scanf("%d%d%d",&u[i],&v[i],&w[i]);
            uni(u[i],v[i]);
        }
        for(int i = 1;i <=m;i++)
        {
            int temp = find(i);
            if(t[temp]==0)
            {
                num++;
                t[temp]++;
            }
        }
        if(num!=1)
        {
            printf("?\n");
            continue;
        }
        for(int i = 1;i <= m;i++)
            p[i] = i;
        sort(r,r+n,cmp);
        kruskal();
        printf("%d\n",ans);
    }
    return 0;
}

因为最小生成树的边一定是n-1条边,那么其实我们还可以计算一下边数,在将找到的边加入最小生成树的时候顺便做就行了,那么如果这个边数小于n-1的话,肯定就不是连通图没有最小生成树。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 1000000
int u[M],v[M],p[M],w[M];
int r[M],t[M];
int n,m;
int ans;
int cmp(int a,int b)
{
    return w[a] < w[b];
}
int find(int x)
{
    return p[x]==x?x:p[x]=find(p[x]);
}
bool kruskal()
{
    int sum = 0;
    for(int i = 0;i < n;i++)
    {
        int e = r[i];
        int x = find(u[e]),y = find(v[e]);
        if(x!=y)
        {
            p[x] = y;
            ans += w[e];
            sum++;
        }
    }
    if(sum < m-1)
        return false;
    return true;
}
int main()
{
    while(scanf("%d %d",&n,&m)==2 && n)
    {
        memset(t,0,sizeof(t));
        ans = 0;
        int num = 0;
        for(int i = 1;i <= m;i++) p[i] = i;
        for(int i = 0;i < n;i++) r[i] = i;
        for(int i = 0;i < n;i++)
        {
            scanf("%d%d%d",&u[i],&v[i],&w[i]);
        }
        sort(r,r+n,cmp);
        bool ok = kruskal();
        if(ok)
        printf("%d\n",ans);
        else
        printf("?\n");
    }
    return 0;
}


你可能感兴趣的:(hdu 1863 最小生成树)