7-11 公路村村通 (30 分)

这个题就是最小生成树算法,倒是没有异议,但是被自己坑了很多次QAQ

自己摸出来以前的一个模板直接对着敲上了,不细心把自己坑哭了

问题一:find函树在找到祖先时 , 顺便让所有的节点都是祖先的直接儿子就好了,这样能降低时间复杂度

问题二:判断道路不够的时候,既然所有的节点的直接爸爸都是祖先, 只要有一个直接爸爸也就是f[2000]数组中的任意一个数和其他的不同就说明道路不够不就行了?问题是不行,至于为啥我也很迷,那就每个节点都找找祖先 也就是把f数组都一样换成find函数都相同就完事了

这个板子超级好用,以后最小生成树问题能套版这个绝对好使哈哈哈

//最小生成树算法模板题
#include<bits/stdc++.h>
using namespace std;
struct node
{
    int s,e,cost;
};
node no[10000];//道路数目
bool cmp(node a, node b)
{
    return a.cost<b.cost;
}
int f[10000];//存储每个节点的最终父节点
int n,m;//城镇数目以及候选道路数目
//初始化 一开始所有节点的爸爸都是自己
void init()
{
    for(int i = 0; i <= n; i++)
        f[i] = i;
}
//找到祖先节点
int find(int x)
{
    if(x == f[x])
    {
        return x;
    }
    else
    {
       return f[x] = find(f[x]);
    }
}
//判断一下两个节点是不是在同一颗树上,在一棵树上就不能再连接了
bool same(int x, int y)
{
    return find(x) == find(y);
}
//两颗树连起来,这样的话祖宗只能保留一个
void mix(int x, int y)
{
    int dx = find(x),dy = find(y);
    //printf("%d 的祖先是 %d , %d 的祖先是 %d \n",x,dx,y,dy);
    if(dx != dy)
        f[dx] = dy;
}
//把边从最短到最长排序,祖先一样的边扔了,不一样的连就完事了
int croscer()
{
    sort(no,no+m,cmp);

    int res = 0;
    for(int i = 0 ; i < m ; i++)
    {
        if(same(no[i].s,no[i].e))continue;
        //printf("%d 和 %d 需要连接 花费是%d\n",no[i].s,no[i].e,no[i].cost);
        mix(no[i].s, no[i].e);
        res += no[i].cost;
    }
    return res;
}
int main()
{
    //输入
    scanf("%d%d",&n,&m);
    int a,b,c;
    for(int i = 0 ; i < m ; i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        no[i].s = a;
        no[i].e = b;
        no[i].cost = c;
    }
    init();
    //求解答案

   int ans =  croscer();
   //判断是否全部联通
   bool flag = false;
   int cnt = find(1);
   for(int i = 2 ; i <= n ; i++)
   {
      if(find(i) != cnt)
      {
          flag = true;
          break;
      }
   }
   if(!flag)
   printf("%d",ans);
   else
    printf("-1");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/h201601060805/article/details/82897187