最近zx很烦恼,因为呀,zx看上了一台平板电脑,可是zx并没有那么多的钱。
“那可怎么办呢?”zx心想,“只能重操旧业了啊!”,于是zx又决定开始接单赚钱了。
但是问题来了,zx要熟悉地形呀,他可不想贸然前进,毕竟pls可不是那么好惹的。
现在zx的地图上有若干个地点,zx很清楚有的地点与其他地点联系在一起,但是有的地点zx却没那么了解了。
为了方便接单,他需要使得他地图上的所有点联系在一起,但是如果连起来之后任意点之间走的路太长,zx遇到pls的风险就会增加。
他可不想在接单的时候遇到pls,所以他需要聪明的你的帮助!
Input
数据量较大,建议使用scanf输入。
第一行包含测试用例的数量。
每个测试用例以三个整数n,m,k开始(3 <= n <= 500, 0 <= m <= 25000, 0 <= k <= 100)——n代表地点数量(从1 - n编号),m代表边数。
之后m行 每行三个整数u, v, w (0 <= w <= 1000)——代表编号 u 与 v 的地点之间有一条权值为w的边(数据有重边)。
之后k行 每行第一个整数 t (2 <= t <= n) ——代表zx已经知道 t 个地点之间联系在了一起,往后 t 个整数代表地点的编号。
Output
对于每个样例,zx想要使地图上所有的点联系在一起同时保证遇到pls的风险最小,输出还需要连接的边长总和。
如果不可能将所有点联系在一起,则输出-1。
Sample Input
2
7 7 2
1 3 2
2 3 1
3 5 5
4 3 3
7 4 6
4 6 3
2 7 4
3 4 5 6
2 2 3
4 3 1
1 2 3
2 3 1
1 3 2
3 1 2 3
Sample Output
9
-1
很明显的最小生成树,因为不想敲prime了 ,写了一发克鲁斯卡尔,就过了。其中也有一些技巧吧。就是在最后判断到不了的情况,如果是一个集合的话,就是会到达的,不是一个集合的话,是不会到达的,最后再判断了一下集合的数量,再输出结果。
#include<iostream>
using namespace std;
#include<bits/stdc++.h>
const int maxn=25005;
typedef long long ll;
typedef pair<int,int> p;
const int inf=1000000;
int n,m,k;
int pre[maxn];
typedef struct
{
int a,b,val;
}point;
point dian[maxn];
bool cmp(point a,point b)
{
return a.val<b.val;
}
int find(int x)
{
return x==pre[x]?x:pre[x]=find(pre[x]);
}
void join(int x,int y)
{
int a=find(x);
int b=find(y);
if(a!=b)
{
pre[a]=b;
}
}
void init()
{
for(int i=1;i<=n;i++)
pre[i]=i;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
init();
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&dian[i].a,&dian[i].b,&dian[i].val);
}
while(k--)
{
int num,a1,a2;
scanf("%d%d",&num,&a1);
for(int i=1;i<num;i++)
{
scanf("%d",&a2);
join(a1,a2);
}
}
sort(dian,dian+m,cmp);
int ans=0;
for(int i=0;i<m;i++)
{
int fx=find(dian[i].a);
int fy=find(dian[i].b);
if(fx!=fy)
{
pre[fx]=fy;
ans+=dian[i].val;
}
}
int k=0;
for(int i=1;i<=n;i++)
{
if(pre[i]==i)
k++;
}
if(k==1)
printf("%d\n",ans);
else
printf("-1\n");
}
return 0;
}