这个题就是最小生成树算法,倒是没有异议,但是被自己坑了很多次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;
}