最小生成树
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 113 Accepted Submission(s): 11
Problem Description
ap最近学习了最小生成树树之后,向你提了这么一个问题:给一个n个节点的完全图,节点编号从1-n, 如果限制这个完全图的生成树中k个点的度数为1,那么还能否构造出最小生成树呢?
Input
第一行一个正整数T,代表有T组数据
每组数据,第一个两个正整数n, k (2 <= n <= 300, 0 <= k <= n)
接下来n*(n-1)/2行,每行三个正整数ui, vi, wi, 代表节点ui和节点vi之间有一条权值为wi的边 (0 <= wi <= 10000)
最后一行, k个互不相同的数fi, 代表限制度数为1的节点的编号
输入保证给出的是完全图
每组数据,第一个两个正整数n, k (2 <= n <= 300, 0 <= k <= n)
接下来n*(n-1)/2行,每行三个正整数ui, vi, wi, 代表节点ui和节点vi之间有一条权值为wi的边 (0 <= wi <= 10000)
最后一行, k个互不相同的数fi, 代表限制度数为1的节点的编号
输入保证给出的是完全图
Output
每组数据,若符合条件的最小生成树存在,输出该最小生成树所有边权之和; 若不存在, 输出-1
Sample Input
3 3 0 1 2 1 2 3 2 3 1 3 3 1 1 2 1 2 3 2 3 1 3 2 3 3 1 2 1 2 3 2 3 1 3 1 2 3
Sample Output
3 4 -1
解题思路:若度为一的点是所有点,当n等于2的时候,答案就是唯一边权,否则就是形不成最小生成树,若度为一的点小于顶点数,那么先将度不为一的点用最小边连起来,再找和度为一的点最近的边(边的连点都为度为一的点是不能取的)
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <set>
#include <bitset>
#include <stack>
#include <map>
#include <climits>
#include <functional>
using namespace std;
#define LL long long
const int INF=0x3f3f3f3f;
struct node
{
int s,e,w,flag;
}x[90000];
int k,a[350];
int f[350],n;
int sum[350];
int Find(int x)
{
if(f[x]==x) return x;
return f[x]=Find(f[x]);
}
bool cmp(node a,node b)
{
return a.w<b.w;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int p;
memset(a,0,sizeof a);
scanf("%d %d",&n,&k);
for(int i=1;i<=(n-1)*n/2;i++)
scanf("%d %d %d",&x[i].s,&x[i].e,&x[i].w),x[i].flag=0;
for(int i=1;i<=k;i++)
scanf("%d",&p),a[p]=1;
if(n==k)
{
if(n==2) {printf("%d\n",x[1].w);continue;}
else printf("-1\n");
}
for(int i=1;i<=n;i++) f[i]=i;
memset(sum,0,sizeof sum);
sort(x+1,x+1+n*(n-1)/2,cmp);
int cnt=0,ans=0;
for(int i=1;i<=(n-1)*n/2;i++)
{
if(a[x[i].s]) continue;
if(a[x[i].e]) continue;
int ss=Find(x[i].s),ee=Find(x[i].e);
if(ss!=ee)
{
f[ss]=ee;
cnt++;
ans+=x[i].w;
x[i].flag=1;
}
if(cnt==n-1) break;
}
for(int i=1;i<=(n-1)*n/2;i++)
{
if(cnt==n-1) break;
if(x[i].flag) continue;
if(a[x[i].s]&&a[x[i].e]) continue;
if(a[x[i].s]&&sum[x[i].s]) continue;
if(a[x[i].e]&&sum[x[i].e]) continue;
int ss=Find(x[i].s),ee=Find(x[i].e);
if(ss!=ee)
{
if(a[x[i].s]) sum[x[i].s]++;
else if(a[x[i].e]) sum[x[i].e]++;
f[ss]=ee;
cnt++;
ans+=x[i].w;
}
if(cnt==n-1) break;
}
printf("%d\n",ans);
}
return 0;
}