最小生成树变形
将边倒序排列,
从大的边开始遍历,
如果查的时候发现两个连通分量都具有危险点,那么该边该删;
否则将两个连通分量并成一个连通分量。
照着书上的模板打,因为将i,j定义成了全局变量,所以出现了bug.TLE了多次。
改正后AC,附AC代码:
View Code
#include <iostream> #include <string.h> #include <stdio.h> #include <math.h> #include <stdlib.h> #include <algorithm> using namespace std; #define MAXN 100500 struct edge{ int u,v,w; }edges[MAXN]; int parent[MAXN]; int vis[MAXN]; int n,k; long long sumweight; void UFset(){ for(int i=0;i<n;i++){ parent[i]=-1; } } int Find(int x){ int s; for(s=x;parent[s]>=0;s=parent[s]); while(s!=x){ int tmp=parent[x]; parent[x]=s; x=tmp; } return s; } void Union(int R1,int R2){ int r1=Find(R1),r2=Find(R2); int tmp=parent[r1]+parent[r2]; if(vis[r1]==1){ parent[r2]=r1; parent[r1]=tmp; } else{ parent[r1]=r2; parent[r2]=tmp; } } int cmp(const void *a,const void *b){ edge aa=*(const edge *)a; edge bb=*(const edge *)b; return bb.w-aa.w; } void Kruskal(){ int u,v; UFset(); for(int i=0;i<n-1;i++){ u=edges[i].u;v=edges[i].v; if(vis[Find(u)]==1 && vis[Find(v)]==1){ sumweight+=edges[i].w; } else{ Union(u,v); } } } int main(){ //freopen("in.txt","r",stdin); int a,b,c,mac; int ncas; scanf("%d",&ncas); while(ncas--){ scanf("%d%d",&n,&k); for(int i=0;i<n-1;i++){ scanf("%d%d%d",&a,&b,&c); edges[i].u=a; edges[i].v=b; edges[i].w=c; } memset(vis,0,sizeof(vis)); for(int i=0;i<k;i++){ scanf("%d",&mac); vis[mac]=1; } qsort(edges,n-1,sizeof(edges[0]),cmp); sumweight=0; Kruskal(); printf("%I64d\n",sumweight); } return 0; }
杭电OJ真是奇葩,
1.C++比G++快;
2.不支持%lld,输入或输出要用%I64d。定义用long long就成。
接下来要把所有与生成树有关的算法都学一下,刷一些与生成树有关的题。
该题还可以用树形DP做,近期要学一下树形DP。