最小生成树练习2(Kruskal)
hdu4786 Fibonacci Tree(生成树)问能否用白边和黑边构成一棵生成树,并且白边数量是斐波那契数。
题解:分别优先加入白边和黑边,求出生成树能包含白边的最大值和最小值,其间有值为斐波那契数即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int M=1e5+1; 6 const int N=1e5+1; 7 struct edge{ 8 int u,v,w; 9 }e[M]; 10 int f[N]; 11 int fi[20]; 12 int n,m,ans; 13 int cmp(edge a,edge b){ 14 return a.w<b.w; 15 } 16 void init(){ 17 for(int i=1;i<=n;++i) f[i]=i; 18 } 19 int fin(int x){ 20 if(x!=f[x])f[x]=fin(f[x]); 21 return f[x]; 22 } 23 void Kruskal(){ 24 int u,v,i,cnt=0,mi=0,ma=0,flag=0; 25 init(); 26 for(i=0;i<m;++i){ 27 u=e[i].u; 28 v=e[i].v; 29 if((u=fin(u))!=(v=fin(v))){ 30 f[u]=v; 31 if(e[i].w) mi++; 32 if(++cnt==n-1){flag=1;break;} 33 } 34 } 35 if(!flag){printf("No\n");return;} 36 init(); 37 for(i=m-1;i>=0;--i){ 38 u=e[i].u; 39 v=e[i].v; 40 if((u=fin(u))!=(v=fin(v))){ 41 f[u]=v; 42 if(e[i].w) ma++; 43 if(++cnt==n-1)break; 44 } 45 } 46 for(i=1;i<20;++i) 47 if(mi<=fi[i]&&fi[i]<=ma){ 48 printf("Yes\n");return; 49 } 50 printf("No\n"); 51 } 52 int main(){ 53 int t,i,a,b,c,k=1; 54 fi[1]=1;fi[2]=2; 55 for(i=3;i<20;++i) 56 fi[i]=fi[i-1]+fi[i-2]; 57 //printf(".%d.",fi[19]); 58 scanf("%d",&t); 59 while(t--){ 60 scanf("%d%d",&n,&m); 61 for(i=0;i<m;++i){ 62 scanf("%d%d%d",&a,&b,&c); 63 e[i]={a,b,c}; 64 } 65 sort(e,e+m,cmp); 66 printf("Case #%d: ",k++); 67 Kruskal(); 68 } 69 return 0; 70 }
hdu5253 连接的管道(最小生成树)一开始我因为没建好图纠结了ToT~
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 using namespace std; 5 const int N=1000; 6 struct edge{ 7 int u,v,w; 8 }e[N*N*2]; 9 int f[N*N]; 10 int g[N][N]; 11 int ei,n,m,ans; 12 int cmp(edge a,edge b){ 13 return a.w<b.w; 14 } 15 int fin(int x){ 16 if(x!=f[x])f[x]=fin(f[x]); 17 return f[x]; 18 } 19 void Kruskal(){ 20 int u,v,i,cnt=0; 21 for(ans=i=0;i<ei;++i){ 22 u=e[i].u; 23 v=e[i].v; 24 if((u=fin(u))!=(v=fin(v))){ 25 f[u]=v; 26 ans+=e[i].w; 27 if(++cnt==n*m-1)break; 28 } 29 } 30 } 31 int main(){ 32 int t,i,j,h,k=1; 33 scanf("%d",&t); 34 while(t--){ 35 ei=0; 36 scanf("%d%d",&n,&m); 37 for(i=0;i<n;++i){ 38 for(j=0;j<m;++j){ 39 scanf("%d",&g[i][j]); 40 f[i*m+j]=i*m+j; 41 if(i>0){ 42 e[ei].u=i*m+j; e[ei].v=(i-1)*m+j; 43 e[ei++].w=abs(g[i][j]-g[i-1][j]); 44 } 45 if(j>0){ 46 e[ei].u=i*m+j; e[ei].v=i*m+j-1; 47 e[ei++].w=abs(g[i][j]-g[i][j-1]); 48 } 49 } 50 } 51 sort(e,e+ei,cmp); 52 Kruskal(); 53 printf("Case #%d:\n%d\n",k++,ans); 54 } 55 return 0; 56 }
hdu1598 find the most comfortable road(最小生成树,枚举)第一眼看过去差点想最短路[吓],,这是最小差不是最短路哦。用Kruskal要对边排序,贪心正好哩。枚举最小道路建树,起点和终点连上了就记录最大边与最小边之差,最后选所有情况的最小值就行啦。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 using namespace std; 5 const int inf=0x3f3f3f3f; 6 const int M=1000; 7 struct edge{ 8 int u,v,w; 9 }e[M]; 10 int f[201]; 11 int n,m,ans,st,ed; 12 int cmp(edge a,edge b){ 13 return a.w<b.w; 14 } 15 void init(){ 16 for(int i=1;i<=n;++i) 17 f[i]=i; 18 } 19 int fin(int x){ 20 if(x!=f[x])f[x]=fin(f[x]); 21 return f[x]; 22 } 23 void Kruskal(){ 24 int u,v,i,j; 25 ans=inf; 26 for(i=0;i<m;++i){//枚举 27 init(); 28 for(j=i;j<m&&e[j].w-e[i].w<ans;++j){ 29 u=e[j].u; 30 v=e[j].v; 31 if((u=fin(u))!=(v=fin(v))){ 32 f[u]=v; 33 } 34 if(fin(st)==fin(ed)){ 35 ans=min(ans,e[j].w-e[i].w); 36 break; 37 } 38 } 39 } 40 } 41 int main(){ 42 int i,j,q; 43 while(scanf("%d%d",&n,&m)==2){ 44 for(i=0;i<m;++i) 45 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 46 sort(e,e+m,cmp); 47 scanf("%d",&q); 48 while(q--){ 49 scanf("%d%d",&st,&ed); 50 Kruskal(); 51 printf("%d\n",(ans==inf)?-1:ans); 52 } 53 } 54 return 0; 55 }
poj3522 Slim Span(最小生成树,枚举)求最大边与最小边之差最小的生成树。和上面那题挺像的,相比之下,这题就是完整的最小生成树了。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 using namespace std; 5 const int inf=0x3f3f3f3f; 6 const int N=101; 7 struct edge{ 8 int u,v,w; 9 }e[5000]; 10 int f[N]; 11 int n,m,ans,st,ed; 12 int cmp(edge a,edge b){ 13 return a.w<b.w; 14 } 15 void init(){ 16 for(int i=1;i<=n;++i) 17 f[i]=i; 18 } 19 int fin(int x){ 20 if(x!=f[x])f[x]=fin(f[x]); 21 return f[x]; 22 } 23 void Kruskal(){ 24 int u,v,i,j,cnt; 25 ans=inf; 26 for(i=0;i<m;++i){ 27 init(); cnt=0; 28 for(j=i;j<m&&e[j].w-e[i].w<ans;++j){ 29 u=e[j].u; 30 v=e[j].v; 31 if((u=fin(u))!=(v=fin(v))){ 32 f[u]=v; 33 if(++cnt==n-1){ 34 ans=min(ans,e[j].w-e[i].w); 35 break; 36 } 37 } 38 } 39 } 40 } 41 int main(){ 42 int i,j,q; 43 while(scanf("%d%d",&n,&m),n||m){ 44 for(i=0;i<m;++i) 45 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 46 sort(e,e+m,cmp); 47 Kruskal(); 48 printf("%d\n",(ans==inf)?-1:ans); 49 } 50 return 0; 51 }
poj2784 Buy or Build(最小生成树,二进制枚举)英语渣在艰难地读题orz。已知n个城市的坐标,q个连通块各自的费用,新建一条边的费用为两点距离的平方。求最小生成树。学了一下二进制枚举法。
1 #include<cstdio> 2 #include<algorithm> 3 #include<vector> 4 using namespace std; 5 const int N=1001; 6 struct edge{ 7 int u,v,w; 8 }e[500000]; 9 struct node{ 10 int x,y; 11 }V[N]; 12 int f[N]; 13 int a[10]; 14 int n,m,q; 15 vector<int>g[10]; 16 int cmp(edge a,edge b){ 17 return a.w<b.w; 18 } 19 int dist(int i,int j){ 20 return (V[i].x-V[j].x)*(V[i].x-V[j].x)+(V[i].y-V[j].y)*(V[i].y-V[j].y); 21 } 22 void init(){ 23 for(int i=1;i<=n;++i) 24 f[i]=i; 25 } 26 int fin(int x){ 27 if(x!=f[x])f[x]=fin(f[x]); 28 return f[x]; 29 } 30 void uni(int x,int y){ 31 if((x=fin(x))==(y=fin(y)))return; 32 f[x]=y; 33 } 34 int Kruskal(){ 35 int u,v,i,j,cnt=0,ans=0; 36 for(i=0;i<m;++i){ 37 u=e[i].u; 38 v=e[i].v; 39 if((u=fin(u))!=(v=fin(v))){ 40 f[u]=v; 41 ans+=e[i].w; 42 if(++cnt==n-1)break; 43 } 44 } 45 //printf("%d..\n",ans); 46 return ans; 47 } 48 void solve(){ 49 int i,j,k,cost,ans; 50 init(); 51 ans=Kruskal(); 52 for(i=0;i<(1<<q);++i){//枚举方案 53 cost=0; 54 init(); 55 for(j=0;j<q;++j){ 56 if(!((i>>j)&1))continue;//二进制枚举 57 cost+=a[j]; 58 //printf("COST:%d..",cost); 59 for(k=1;k<g[j].size();++k) 60 uni(g[j][k],g[j][0]); 61 } 62 ans=min(ans,cost+Kruskal()); 63 } 64 printf("%d\n",ans); 65 } 66 int main(){ 67 int i,j,num,x; 68 while(scanf("%d%d",&n,&q)==2){ 69 for(i=0;i<q;++i){ 70 g[i].clear(); 71 scanf("%d%d",&num,&a[i]); 72 for(j=0;j<num;++j){ 73 scanf("%d",&x); 74 g[i].push_back(x); 75 } 76 } 77 for(i=1;i<=n;++i) scanf("%d%d",&V[i].x,&V[i].y); 78 m=0; 79 for(i=1;i<n;++i){ 80 for(j=i+1;j<=n;++j){ 81 e[m].u=i; e[m].v=j; 82 e[m++].w=dist(i,j); 83 } 84 } 85 sort(e,e+m,cmp); 86 solve(); 87 } 88 return 0; 89 }