kuangbin最小生成树专题
网址:https://vjudge.net/contest/66965#overview
第一题:
poj1251
裸最小生成树
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int maxn=100500; struct node { int x; int y; int w; }a[maxn]; int n,k; char s,v; int cnt; int w; int f[30]; int findf(int x) { if(f[x]==x) return x; else { //f[x]=findf(f[x]); return findf(f[x]); } } int join(int x,int y) { int t1=findf(x); int t2=findf(y); if(t1==t2) return 1; else { f[t2]=t1; return 0; } } int cmp(node x,node y) { return x.w<y.w; } int main() { while(cin>>n) { if(n==0) break; for(int i=1;i<=30;i++) f[i]=i; cnt=0; for(int i=1;i<n;i++) { cin>>s>>k; for(int i=1;i<=k;i++) { cin>>v>>w; a[++cnt].x=s-'A'+1; a[cnt].y=v-'A'+1; a[cnt].w=w; } } sort(a+1,a+1+cnt,cmp); int cot=0; int cost=0; for(int i=1;i<=cnt;i++) { if(join(a[i].x,a[i].y)==0) { cot++;cost+=a[i].w; } if(cot==n-1) break; } cout<<cost<<endl; } }
第二题
poj1287
裸最小生成树
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int maxn=100500; struct node { int x,y,w; }a[maxn]; int f[100]; int cnt,cot; int n,m; int x,y,w; bool cmp(node xx,node yy) { return xx.w<yy.w; } int findf(int u) { if(f[u]==u) return u; else { f[u]=findf(f[u]); return f[u]; } } bool join(int u,int v) { int t1=findf(u); int t2=findf(v); if(t1==t2) { return false; } else { f[t2]=t1; return true; } } int main() { while(cin>>n>>m) { if(n==0) break; for(int i=1;i<=m;i++) { cin>>x>>y>>w; a[i].x=x; a[i].y=y; a[i].w=w; } sort(a+1,a+1+m,cmp); for(int i=1;i<=n;i++) f[i]=i; cnt=0; int cost=0; for(int i=1;i<=m;i++) { if(join(a[i].x,a[i].y)) { cnt++; cost+=a[i].w; if(cnt==n-1) break; } } cout<<cost<<endl; } }
第三题
poj2031
最小生成树+圆的距离
#include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<cstdio> using namespace std; const int maxn=20050; struct node { int x,y; double w; }a[maxn]; struct circle { double x,y,z,r; }c[205]; int f[205]; int n; int cnt; int findf(int u) { if(f[u]==u) return u; else { f[u]=findf(f[u]); return f[u]; } } bool join(int u,int v) { int t1=findf(u); int t2=findf(v); if(t1==t2) { return false; } else { f[t2]=t1; return true; } } bool cmp(node u,node v) { return u.w<v.w; } double juage(int u,int v) { double tmp=sqrt((c[u].x-c[v].x)*(c[u].x-c[v].x)+(c[u].y-c[v].y)*(c[u].y-c[v].y)+(c[u].z-c[v].z)*(c[u].z-c[v].z)); if(tmp<=(c[u].r+c[v].r)) return 0; else { double ans=tmp-c[u].r-c[v].r; return ans; } } int main() { while(cin>>n) { int cot=0; if(n==0) break; for(int i=1;i<=n;i++) { cin>>c[i].x>>c[i].y>>c[i].z>>c[i].r; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(i==j) continue; else { a[++cot].x=i;a[cot].y=j;a[cot].w=juage(i,j); } } for(int i=1;i<=n;i++) sort(a+1,a+1+cot,cmp); for(int i=1;i<=n;i++) f[i]=i; cnt=0; double cost=0; for(int i=1;i<=cot;i++) { if(join(a[i].x,a[i].y)) { cost+=a[i].w; cnt++; } if(cnt==n-1) break; } printf("%.3f\n",cost); } }
第四题:
poj2421
部分边+最小生成树,先把给出的边扔进并查集里
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> using namespace std; const int maxn=100500; struct node { int x,y,w; }a[maxn]; int g[105][105]; int n,cnt; int f[105]; int cmp(node x,node y) { return x.w<y.w; } int findf(int u) { if(f[u]==u) return u; else { f[u]=findf(f[u]); return f[u]; } } bool join(int u,int v) { int t1=findf(u); int t2=findf(v); if(t1==t2) return false; else { f[t2]=t1; return true; } } int main() { int x,y; cin>>n; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>g[i][j]; int cost=0; int cot=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(i==j) continue; a[++cot].x=i;a[cot].y=j;a[cot].w=g[i][j]; } sort(a+1,a+1+cot,cmp); for(int i=1;i<=n;i++) f[i]=i; int q; cin>>q; while(q--) { cin>>x>>y; if(join(x,y)) { cnt++; } join(x,y); } for(int i=1;i<=cot;i++) { if(cnt==n-1) break; else { if(join(a[i].x,a[i].y)) { cnt++; cost+=a[i].w; } } } cout<<cost<<endl; }
第五题:
zoj1586
用prime写的,把边权改成正常边权+点权
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int maxn=1005; const int inf=0x3f3f3f3f; struct node { int num; int dist; node(int _num=0,int _dist=0):num(_num),dist(_dist){} friend bool operator<(node a,node b) { return a.dist>b.dist; } }; struct Edge { int next; int to; int w; }edge[maxn*maxn]; int g[maxn][maxn]; int c[maxn]; int n; int visit[maxn]; int dist[maxn]; int head[maxn]; int cnt; void add(int u,int v,int w) { edge[cnt].next=head[u]; edge[cnt].to=v; edge[cnt].w=w; head[u]=cnt++; } int prime(int u) { int cost=0; fill(dist+1,dist+1+n,inf); fill(visit+1,visit+1+n,0); dist[u]=0; priority_queue<node>q; q.push(node(u,dist[u])); while(!q.empty()) { node x=q.top();q.pop(); int now=x.num; if(visit[now]) continue; visit[now]=1; cost+=dist[now]; for(int i=head[now];i!=-1;i=edge[i].next) { int v=edge[i].to; if(visit[v]) continue; if(dist[v]>edge[i].w) { dist[v]=edge[i].w; q.push(node(v,dist[v])); } } } return cost; } void init() { memset(head,-1,sizeof(head)); cnt=0; } int main() { int t; scanf("%d",&t); while(t--) { int start=inf; int pos=1; init(); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&c[i]); if(start<c[i]) { start=c[i]; pos=i; } } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&g[i][j]); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(i==j) continue; else { add(i,j,g[i][j]+c[i]+c[j]); } } } int ans=prime(pos); cout<<ans<<endl; } }
第六题
poj1789
裸最小生成树
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int maxn=2050; const int inf=0x3f3f3f3f; struct node { int num; int dist; node(int _num=0,int _dist=0):num(_num),dist(_dist){} friend bool operator<(node a,node b) { return a.dist>b.dist; } }; struct Edge { int next,to,w; }edge[maxn*maxn]; int head[maxn]; int cnt; int dist[maxn]; int visit[maxn]; int n; char s[maxn][10]; void add(int u,int v,int w) { edge[cnt].next=head[u]; edge[cnt].to=v; edge[cnt].w=w; head[u]=cnt++; } int prime(int u) { int cost=0; fill(dist+1,dist+1+n,inf); fill(visit+1,visit+1+n,0); dist[u]=0; priority_queue<node>q; q.push(node(u,dist[u])); while(!q.empty()) { node x=q.top();q.pop(); int now=x.num; if(visit[now]) continue; visit[now]=1; cost+=dist[now]; for(int i=head[now];i!=-1;i=edge[i].next) { int v=edge[i].to; if(visit[v]) continue; if(dist[v]>edge[i].w) { dist[v]=edge[i].w; q.push(node(v,dist[v])); } } } return cost; } int main() { while(scanf("%d",&n)!=EOF) { if(n==0) break; memset(head,-1,sizeof(head)); cnt=0; int tmp; for(int i=1;i<=n;i++) scanf("%s",s[i]); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { tmp=0; if(i==j) continue; for(int k=0;k<7;k++) { if(s[i][k]!=s[j][k]) tmp++; } add(i,j,tmp); } } int ans=prime(1); printf("The highest possible quality is 1/%d.\n",ans); } }
第七题
poj2349
反着来,每一个s可以减少s-1条边,先处理s,然后就行了
#include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<cstdio> using namespace std; const int maxn=505; struct node { int x,y; double w; }a[maxn*maxn]; int cot,cnt; double ans; int s,p; double x[maxn],y[maxn]; int f[maxn]; int findf(int u) { if(f[u]==u) return u; else { f[u]=findf(f[u]); return f[u]; } } bool join(int u,int v) { int t1=findf(u); int t2=findf(v); if(t1==t2) { return false; } else { f[t2]=t1; return true; } } bool cmp(node u,node v) { return u.w<v.w; } int tt; int main() { cin>>tt; while(tt--) { ans=cot=cnt=0; cin>>s>>p; for(int i=1;i<=p;i++) cin>>x[i]>>y[i]; for(int i=1;i<=p;i++) { for(int j=1;j<=p;j++) { if(i==j) continue; else { a[++cot].x=i;a[cot].y=j;a[cot].w=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])); } } } sort(a+1,a+1+cot,cmp); for(int i=1;i<=p;i++) f[i]=i; if(s>0) s--; for(int i=1;i<=cot;i++) { if(cnt+s>=p-1) break; if(join(a[i].x,a[i].y)) { cnt++; ans=a[i].w; } } printf("%.2f\n",ans); } }
第八题
poj1751
这道题容易超时,尽量别用浮点数,两个之间的距离可以直接用整数
#include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<cstdio> using namespace std; const int maxn=800; struct node { int x,y; double w; }a[maxn*maxn]; int cot,cnt; int n,k; int x[maxn],y[maxn]; int f[maxn]; int findf(int u) { if(f[u]==u) return u; else { f[u]=findf(f[u]); return f[u]; } } bool join(int u,int v) { int t1=findf(u); int t2=findf(v); if(t1==t2) { return false; } else { f[t2]=t1; return true; } } bool cmp(node u,node v) { return u.w<v.w; } int tt; int main() { int tx,ty; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(i==j) continue; a[++cot].x=i;a[cot].y=j;a[cot].w=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]); } sort(a+1,a+1+cot,cmp); for(int i=1;i<=n;i++) f[i]=i; int tmp=0; scanf("%d",&k); for(int i=1;i<=k;i++) { scanf("%d%d",&tx,&ty); if(join(tx,ty)) { tmp++; } join(tx,ty); } for(int i=1;i<=cot;i++) { if(tmp+cnt>=(n-1)) break; if(join(a[i].x,a[i].y)) { cnt++; printf("%d %d\n",a[i].x,a[i].y); } } }
第九题:
裸最小生成树
#include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<cstdio> using namespace std; const int maxn=110; struct node { int x,y,w; }a[maxn*maxn]; int cot,cnt,ans; int n,k; int x[maxn][maxn]; int f[maxn]; int findf(int u) { if(f[u]==u) return u; else { f[u]=findf(f[u]); return f[u]; } } bool join(int u,int v) { int t1=findf(u); int t2=findf(v); if(t1==t2) { return false; } else { f[t2]=t1; return true; } } bool cmp(node u,node v) { return u.w<v.w; } int tt; int main() { while(scanf("%d",&n)!=EOF) { cot=ans=cnt=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&x[i][j]); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(i==j) continue; a[++cot].x=i;a[cot].y=j;a[cot].w=x[i][j]; } } sort(a+1,a+1+cot,cmp); for(int i=1;i<=n;i++) f[i]=i; for(int i=1;i<=cot;i++) { if(join(a[i].x,a[i].y)) { cnt++; ans+=a[i].w; } if(cnt==n-1) break; } printf("%d\n",ans); } }
第十题
最小生成树+BFS预处理
题意:就是每次到A,S就可以分其他路径
注意这题有个傻逼地方,m,n输完后,n后面跟着一串空格。。这个要自己注意,我是拿gets直接输掉了
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int inf=0x3f3f3f3f; const int maxn=100500; struct node { int num; int dist; node(int _num,int _dist):num(_num),dist(_dist){} friend bool operator<(node a,node b) { return a.dist>b.dist; } }; struct Edge { int next,to,w; }edge[maxn]; struct Node { int x,y,s; }que[2505]; char s[550][550]; int dist[2505]; bool visit[2505]; bool vis[550][550]; int next[4][2]={{1,0},{0,1},{-1,0},{0,-1}}; int n,m,cnt,Start,End; int head[maxn]; void add(int u,int v,int w) { edge[cnt].next=head[u];edge[cnt].to=v;edge[cnt].w=w;head[u]=cnt++; edge[cnt].next=head[v];edge[cnt].to=u;edge[cnt].w=w;head[v]=cnt++; } void bfs(int st,int en) { memset(vis,0,sizeof(vis)); int tail,head; int tx,ty; tail=head=1; vis[st][en]=1; que[tail].x=st;que[tail].y=en;que[tail].s=0; tail++; while(head<tail) { for(int i=0;i<=3;i++) { tx=que[head].x+next[i][0]; ty=que[head].y+next[i][1]; if(tx<1||tx>n||ty<1||ty>m) continue; if(s[tx][ty]!='#'&&vis[tx][ty]==0) { que[tail].x=tx; que[tail].y=ty; que[tail].s=que[head].s+1; vis[tx][ty]=1; if(s[tx][ty]=='A'||s[tx][ty]=='S') add((st-1)*m+en,(tx-1)*m+ty,que[tail].s); tail++; } } head++; } } int prime(int u) { memset(dist,inf,sizeof(dist)); memset(visit,0,sizeof(visit)); int sum=0; int lowcast=0; priority_queue<node> q; dist[u]=0; q.push(node(u,dist[u])); while(!q.empty()) { node x=q.top();q.pop(); int now=x.num; if(visit[now]==1) continue; visit[now]=1; sum=sum+dist[now]; for(int i=head[now];i!=-1;i=edge[i].next) { int v=edge[i].to; if(visit[v]==1) continue; if(dist[v]>edge[i].w) { dist[v]=edge[i].w; q.push(node(v,dist[v])); } } } return sum; } int main() { char ss[100]; int T; cin>>T; while(T--) { memset(head,-1,sizeof(head));cnt=0; cin>>m>>n; gets(ss); for(int i=1;i<=n;i++) gets(s[i]+1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(s[i][j]=='S'||s[i][j]=='A') bfs(i,j); if(s[i][j]=='S') Start=i,End=j; } int ans=prime((Start-1)*n+End); printf("%d\n",ans); } }
第十一题
poj1679
裸次小生成树
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> const int inf=0x3f3f3f3f; const int maxn=1005; using namespace std; bool visit[maxn]; int Map[maxn][maxn]; bool used[maxn][maxn];//两个点的那条边是否被使用过; int Max[maxn][maxn];//记录MST中两个点的最大距离; int dist[maxn]; int pre[maxn];//保存父节点; int n,m; int prime() { int ans=0; memset(visit,false,sizeof(visit)); memset(Max,0,sizeof(Max)); memset(used,0,sizeof(used)); visit[1]=1;pre[1]=-1; for(int i=2;i<=n;i++) { dist[i]=Map[1][i]; pre[i]=1; } dist[1]=0; for(int i=1;i<=n-1;i++) { int lowcast=inf; int temp=-1; for(int j=1;j<=n;j++) { if(!visit[j]&&lowcast>dist[j]) { lowcast=dist[j]; temp=j; } } if(lowcast==inf)//这说明有点不连通; return -1; ans+=lowcast;//最小生成树的值; visit[temp]=1; used[temp][pre[temp]]=used[pre[temp]][temp]=1; for(int j=1;j<=n;j++) { if(visit[j]) Max[j][temp]=Max[temp][j]=max(Max[j][pre[temp]],dist[temp]);//数组的作用是记录MST里面两个点的最大距离; if(!visit[j]&&dist[j]>Map[temp][j]) { dist[j]=Map[temp][j]; pre[j]=temp; } } } return ans; } int ans; int SMST() { int minn=inf; for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { if(Map[i][j]!=inf&&(!used[i][j])) { minn=min(minn,ans+Map[i][j]-Max[i][j]); } } } if(minn==inf) return -1;//没有最小生成树; return minn; } int main() { int t; int x,y,w; cin>>t; while(t--) { cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(i==j) Map[i][j]=0; else Map[i][j]=inf; } for(int i=1;i<=m;i++) { cin>>x>>y>>w; Map[x][y]=w;Map[y][x]=w; } ans=prime(); if(ans==-1) { printf("Not Unique!\n"); continue; } if(ans==SMST())printf("Not Unique!\n"); else printf("%d\n",ans); } return 0; }
第十二题
hdu1233
裸最小生成树
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> #define inf 0x3f3f3f3f #define maxn 1005000 using namespace std; struct node { int num; int dist; node(int _num=0,int _dist=0):num(_num),dist(_dist){} friend bool operator<(node a,node b) { if(a.dist==b.dist) return a.num>b.num; return a.dist>b.dist; } }; struct Edge { int next; int to; int w; }edge[maxn]; int dist[100500]; int cnt; int head[maxn]; int visit[100500]; void add(int u,int v,int w) { edge[cnt].next=head[u];edge[cnt].w=w; edge[cnt].to=v;head[u]=cnt++; } int prime(int u) { memset(dist,inf,sizeof(dist)); memset(visit,0,sizeof(visit)); int sum=0; int lowcast=0; priority_queue<node> q; dist[u]=0; q.push(node(u,dist[u])); while(!q.empty()) { node x=q.top();q.pop(); int now=x.num; if(visit[now]==1) continue; visit[now]=1; sum=sum+dist[now]; for(int i=head[now];i!=-1;i=edge[i].next) { int v=edge[i].to; if(visit[v]==1) continue; if(dist[v]>edge[i].w) { dist[v]=edge[i].w; q.push(node(v,dist[v])); } } } return sum; } int main() { int n,m; int x,y,w; while(scanf("%d",&n)&&n) { m=n*(n-1)/2; memset(head,-1,sizeof(head));cnt=0; for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&w); add(x,y,w);add(y,x,w); } int ans=prime(1); printf("%d\n",ans); } }
第十三题
好像和前面一样的,所以没写
第十四题
#include<iostream> #include<algorithm> #include<cstring> #include<math.h> #include<cstdio> const int inf=0x7fffffff; using namespace std; struct node { double x; double y; }a[105]; int n; double Map[105][105]; double dist[105]; bool visit[105]; int flag; double prime(int x) { memset(visit,0,sizeof(visit)); flag=0; int temp=inf; double lowcast; double sum=0; for(int i=1;i<=n;i++) dist[i]=Map[x][i]; visit[x]=1; for(int i=1;i<=n-1;i++) { lowcast=inf; for(int j=1;j<=n;j++) { if(visit[j]==0&&dist[j]<lowcast) { temp=j;lowcast=dist[j]; } } if(temp==inf) { flag=1;break; } visit[temp]=1; sum+=lowcast; if(dist[temp]>1000) flag=1; for(int k=1;k<=n;k++) { if(visit[k]==0&&dist[k]>Map[temp][k]) dist[k]=Map[temp][k]; } } return sum; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(i==j) Map[i][j]=0; else Map[i][j]=inf; } } for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { Map[i][j]=sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y)); Map[j][i]=sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y)); if(Map[i][j]>1000||Map[i][j]<10) { Map[i][j]=inf; Map[j][i]=inf; } } } double x=prime(1); if(flag==1||x>=inf) printf("oh!\n"); else { x=x*100; printf("%.1lf\n",x); } } return 0; }