题意:给定图上一共有n的点,有m天,每天加一条边并且问当前的边集合的最小生成树是多少,没有的话就输出-1;
思路 一开始想的方法是m-(n-1)+1次克鲁斯卡尔
但是直接超时
后来学习了别人的做法
是维持一个动态的n条边 因为我们只用n-1条边 形成一个最小生成树 那么我们把成环的边 就删掉 保证用最后一个去替换要删的点位置
代码如下
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define dbg(x) ;
//cout<<#x<<" = "<< (x)<< endl
const int MAX_N = 100000;
const int MAX_M = 200000;
int eid ,fa[MAX_N],n;
int arr[1025][1025];
struct node
{
int u,v,w;
bool operator< (const node &a) const
{
return w < a.w;
}
}e[MAX_M];
int get(int x)
{
if(fa[x]==x) return x;
return fa[x] = get(fa[x]);
}
void Merge(int x,int y)
{
x = get(x),y = get(y);
if(x!=y)
{
fa[x] = y;
}
return ;
}
void solve()
{
sort(e,e+eid);
int pos =-1,cnt = 0,mst = n,sum = 0;
for(int i = 0;i<eid;++i)
{
int x= get(e[i].u);
int y = get(e[i].v);
if(x==y)
{
pos = i;
continue;
}
else
{
Merge(x,y);
mst--;
sum+=e[i].w;
}
}
if(pos!=-1)
{
e[pos] = e[eid-1];
eid--;
}
if(mst!=1)
printf("-1\n");
else
{
printf("%d\n",sum);
}
}
int main()
{
int t,Kase = 0;
scanf("%d",&t);
while(t--)
{
eid = 0;
printf("Case %d:\n",++Kase);
int m;
scanf("%d%d",&n,&m);
for(int i = 1;i<=m;++i)
{
scanf("%d%d%d",&e[eid].u,&e[eid].v,&e[eid].w);
eid++;
for(int i = 1;i<=n;++i)
fa[i] = i;
solve();
}
}
}