HDU_STEPS 6.1 最小生成树
6.1.1 HDU 1102 Constructing Roads 裸的最小生成树
6.1.2 HDU 1162 Eddy's picture 最小生成树,每两点直接连线建图
6.1.3 HDU 1232 畅通工程 用并查集将图分块,然后修N-1条路即可
6.1.4 HDU 1233 还是畅通工程 还是最小生成树
6.1.5 HDU 1879 继续畅通工程 在已生成部分图的情况下生成最小生成树,输入的时候用并查集合并已经连接的端点
6.1.6 HDU 1301 Jungle Roads 将字母转换成数字建图即可,还是最小生成树
6.1.7 HDU 3371 Connect the Cities
先用并查集将地图分块,连接N块要N-1条路.然后用克鲁斯卡耳生成最小生成树,每合并一次计数加1,说明修了1条路,如果最后修的路的条数<n-1,说明不连通
#include <cstdio> #include <string.h> #include <algorithm> using namespace std; struct edge{ int u,v,w; bool operator <(const edge& ee)const{return w<ee.w;} }e[25005]; int p[505],cas,n,m,k,hash[505]; int find(int x){return x==p[x]?x:p[x]=find(p[x]);} int main(){ scanf("%d",&cas); while(cas--){ scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++)p[i]=i; memset(hash,0,sizeof hash); for(int i=0;i<m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); for(int i=0;i<k;i++){ int t,st,en; scanf("%d%d",&t,&st);t--; while(t--){ scanf("%d",&en); p[find(st)]=find(en); } } int tot=0,cnt=0; for(int i=1;i<=n;i++) if(!hash[find(i)])tot++,hash[find(i)]=1; tot--;//需要增加的边的条数 sort(e,e+m); int res=0; for(int i=0;i<m;i++){ int x=find(e[i].u),y=find(e[i].v); if(x==y)continue; res+=e[i].w; p[x]=y; cnt++; if(cnt==tot)break;//已经连通了 } if(cnt<tot)printf("-1\n"); else printf("%d\n",res); } }
6.1.8 HDU 3367 Pseudoforest
求一个最大生成森林,每个连通块里至多只有一个环
先贪心按从大到小对边排序。如果并入的两个点在一个集合中并且这个集合没有环,就并入这个点并将这个集合标记为有环;如果两个点在不同集合且都有环,就不能加这条边;如果只有一个有环,则并入有环的那部分
#include <cstdio> #include <algorithm> #include <cmath> #define MAXN 10001 using namespace std; struct edge{ int u,v,w,us; edge(){}; edge(int a,int b,int c){u=a,v=b,w=c,us=0;} bool operator<(const edge& e)const{return w>e.w;} }e[MAXN*10]; int p[MAXN],n,m,cir[MAXN]; int find(int x){return x==p[x]?x:p[x]=find(p[x]);} int main(){ while(scanf("%d%d",&n,&m),n||m){ for(int i=0;i<n;i++)p[i]=i; memset(cir,0,sizeof cir); for(int i=0;i<m;i++)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); sort(e,e+m); int res=0; for(int i=0;i<m;i++){ int x=find(e[i].u),y=find(e[i].v); if(x==y&&cir[x]==0){//如果两点在同一个块且无环 cir[x]=1; res+=e[i].w; } if(cir[x]&&cir[y])continue;//如果都有环就不能连了 if(cir[x])p[y]=x;//如果x有环,将y并入x中 else p[x]=y; //否则将x并入y中 res+=e[i].w; } printf("%d\n",res); } }