专题地址:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66965#overview
A 裸的最小生成树,Kruskal算法。
#define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int maxn=3000; const int maxm=100000; int parent[maxn]; int tot; struct Edge { int u,v,w; }edge[maxm]; void addedge(int u,int v,int w) { edge[tot].u=u; edge[tot].v=v; edge[tot++].w=w; } int find(int x) {/* if(parent[x]==x) return x; parent[x]=find(parent[x]); return parent[x];*/ return parent[x]==x?x:find(parent[x]); } bool cmp(Edge a,Edge b) { return a.w<b.w; } void init(int n) { for(int i=0;i<=n;i++) parent[i]=i; tot=0; } int kruscal(int n) { sort(edge,edge+tot,cmp); int cnt=0; int ans=0; for(int i=0;i<tot;i++) { int u=edge[i].u; int v=edge[i].v; int w=edge[i].w; int t1=find(u); int t2=find(v); if(t1!=t2) { parent[t1]=t2; ans+=w; cnt++; } if(cnt==n-1) break; } if(cnt<n-1) return -1; else return ans; } int n; int main() { while(rd(n)!=EOF&&n) { char ch;int m; init(n); for(int i=1;i<=n-1;i++) { cin>>ch; int u=ch-'A'+1; rd(m); char to;int w; while(m--) { cin>>to; int v=to-'A'+1; rd(w); addedge(u,v,w); } } printf("%d\n",kruscal(n)); } return 0; }
#define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int maxn=60; const int inf=0x3f3f3f3f; int cost[maxn][maxn]; bool vis[maxn]; int lowc[maxn]; int n,m; int Prim(int cost[][maxn],int n) { int ans=0; memset(vis,0,sizeof(vis)); vis[0]=true; for(int i=1;i<n;i++) lowc[i]=cost[0][i]; for(int i=1;i<n;i++) { int minc=inf; int p=-1; for(int j=0;j<n;j++) if(!vis[j]&&minc>lowc[j]) { minc=lowc[j]; p=j; } if(minc==inf) return -1;//不连通 ans+=minc; vis[p]=true; for(int j=0;j<n;j++) if(!vis[j]&&lowc[j]>cost[p][j]) lowc[j]=cost[p][j]; } return ans; } int main() { while(rd(n)!=EOF&&n) { rd(m); int u,v,w; memset(cost,inf,sizeof(cost)); while(m--) { rd3(u,v,w); u--;v--; if(w<cost[u][v]) { cost[u][v]=w; cost[v][u]=w; } } printf("%d\n",Prim(cost,n)); } return 0; }
#define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int maxn=110; double cost[maxn][maxn]; bool vis[maxn]; const double inf=1000000; const double eps=1e-8; double lowc[maxn]; struct Point { double x,y,z,r; void input() { scanf("%lf%lf%lf%lf",&x,&y,&z,&r); } double distance(Point p) { double dis=sqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y)+(z-p.z)*(z-p.z)); if(dis-r-p.r>eps) return dis-r-p.r; else return 0; } }point[maxn]; int n; double Prim(double cost[][maxn],int n) { memset(vis,0,sizeof(vis)); double ans=0; vis[0]=1; for(int i=1;i<n;i++) lowc[i]=cost[0][i]; for(int i=1;i<n;i++) { double minc=inf; int p=-1; for(int j=0;j<n;j++) { if(minc>lowc[j]&&!vis[j]) { p=j; minc=lowc[j]; } } ans+=minc; vis[p]=1; for(int j=0;j<n;j++) { if(!vis[j]&&lowc[j]>cost[p][j]) lowc[j]=cost[p][j]; } } return ans; } int main() { while(rd(n)!=EOF&&n) { for(int i=0;i<n;i++) { point[i].input(); } for(int i=0;i<n;i++) for(int j=0;j<n;j++) cost[i][j]=inf; for(int i=0;i<n;i++) for(int j=0;j<n;j++) { double dis=point[i].distance(point[j]); if(dis<cost[i][j]) cost[i][j]=cost[j][i]=dis; } printf("%.3f\n",Prim(cost,n)); } return 0; }
#define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int maxn=104; const int inf=0x3f3f3f3f; int cost[maxn][maxn]; int lowc[maxn]; bool vis[maxn]; int n,m; int Prim(int cost[][maxn],int n) { int ans=0; memset(vis,0,sizeof(vis)); vis[0]=true; for(int i=1;i<n;i++) lowc[i]=cost[0][i]; for(int i=1;i<n;i++)//寻找这么多次 { int p=-1,minc=inf; for(int j=0;j<n;j++) { if(minc>lowc[j]&&!vis[j]) { minc=lowc[j]; p=j; } } vis[p]=1; ans+=minc; for(int j=0;j<n;j++) { if(!vis[j]&&lowc[j]>cost[p][j]) lowc[j]=cost[p][j]; } } return ans; } int main() { rd(n); memset(cost,inf,sizeof(cost)); for(int i=0;i<n;i++) for(int j=0;j<n;j++) { rd(cost[i][j]); } rd(m); int u,v; while(m--) { rd2(u,v); u--;v--; cost[u][v]=cost[v][u]=0; } printf("%d\n",Prim(cost,n)); return 0; }
#define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int maxn=1004; const int inf=0x3f3f3f3f; int cost[maxn][maxn]; int lowc[maxn]; bool vis[maxn]; int val[maxn]; int n,m; int Prim(int cost[][maxn],int n) { int ans=0; memset(vis,0,sizeof(vis)); vis[0]=true; for(int i=1;i<n;i++) lowc[i]=cost[0][i]; for(int i=1;i<n;i++)//寻找这么多次 { int p=-1,minc=inf; for(int j=0;j<n;j++) { if(minc>lowc[j]&&!vis[j]) { minc=lowc[j]; p=j; } } vis[p]=1; ans+=minc; for(int j=0;j<n;j++) { if(!vis[j]&&lowc[j]>cost[p][j]) lowc[j]=cost[p][j]; } } return ans; } int main() { int t;rd(t); while(t--) { rd(n); memset(cost,inf,sizeof(cost)); for(int i=0;i<n;i++) rd(val[i]); for(int i=0;i<n;i++) for(int j=0;j<n;j++) { rd(cost[i][j]); cost[i][j]+=val[i]+val[j]; } printf("%d\n",Prim(cost,n)); } return 0; }
F 给出N个长度为7的字符串,两个字符串之间定义距离为 两个字符串每个位置字母不同的个数,一个字符串可以生成另一个字符串,代价为两个字符串的距离,问这n个字符串最小的代价。 把任意两个字符串之间的距离求出来,然后进行最小生成树。
#define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int maxn=2002; const int inf=0x3f3f3f3f; int cost[maxn][maxn]; int lowc[maxn]; bool vis[maxn]; string str[maxn]; int n; int cal(int i,int j) { int cnt=0; for(int k=0;k<7;k++) if(str[i][k]!=str[j][k]) cnt++; return cnt; } int Prim(int cost[][maxn],int n) { int ans=0; memset(vis,0,sizeof(vis)); vis[0]=1; for(int i=1;i<n;i++) lowc[i]=cost[0][i]; for(int i=1;i<n;i++) { int minc=inf,p=-1; for(int j=0;j<n;j++) { if(!vis[j]&&minc>lowc[j]) { minc=lowc[j]; p=j; } } vis[p]=1; ans+=minc; for(int j=0;j<n;j++) { if(!vis[j]&&lowc[j]>cost[p][j]) lowc[j]=cost[p][j]; } } return ans; } int main() { while(rd(n)!=EOF&&n) { for(int i=0;i<n;i++) cin>>str[i]; memset(cost,inf,sizeof(cost)); for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) { int w=cal(i,j); if(w<cost[i][j]) cost[i][j]=cost[j][i]=w; } printf("The highest possible quality is 1/%d.\n",Prim(cost,n)); } return 0; }
#define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int maxn=510; const double inf=100000000.0; double cost[maxn][maxn]; double lowc[maxn]; bool vis[maxn]; double edge[maxn]; struct Point { double x,y; void input() { scanf("%lf%lf",&x,&y); } double distance(Point p) { return hypot(x-p.x,y-p.y); } }point[maxn]; int n,P; double Prim(double cost[][maxn],int n) { memset(vis,0,sizeof(vis)); vis[0]=1; for(int i=1;i<n;i++) lowc[i]=cost[0][i]; int cnt=0; for(int i=1;i<n;i++) { double minc=inf; int p=-1; for(int j=0;j<n;j++) { if(!vis[j]&&minc>lowc[j]) { minc=lowc[j]; p=j; } } edge[cnt++]=minc; vis[p]=1; for(int j=0;j<n;j++) { if(!vis[j]&&lowc[j]>cost[p][j]) lowc[j]=cost[p][j]; } } sort(edge,edge+cnt);//别忘了排序 return edge[cnt-P]; } int main() { int t;rd(t); while(t--) { rd2(P,n); for(int i=0;i<n;i++) point[i].input(); for(int i=0;i<n;i++) for(int j=0;j<n;j++) cost[i][j]=inf; for(int i=0;i<n;i++) for(int j=0;j<n;j++) { double dis=point[i].distance(point[j]); if(dis<cost[i][j]) cost[i][j]=cost[j][i]=dis; } printf("%.2f\n",Prim(cost,n)); } return 0; }
#define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int maxn=1000; const int inf=0x3f3f3f3f; bool vis[maxn]; int cost[maxn][maxn]; int lowc[maxn]; int pre[maxn]; int n,m; struct Point { int x,y; int distance(Point p) { return (x-p.x)*(x-p.x)+(y-p.y)*(y-p.y); } }point[maxn]; void Prim() { memset(vis,0,sizeof(vis)); for(int i=1;i<n;i++) { lowc[i]=cost[0][i]; pre[i]=0; } vis[0]=1;int p=-1; for(int i=1;i<n;i++) { int minc=inf; for(int j=0;j<n;j++) { if(!vis[j]&&minc>lowc[j]) { minc=lowc[j]; p=j; } } vis[p]=1; if(cost[pre[p]][p]) printf("%d %d\n",pre[p]+1,p+1); for(int j=0;j<n;j++) { if(lowc[j]>cost[p][j]&&!vis[j]) { lowc[j]=cost[p][j]; pre[j]=p; } } } } int main() { rd(n); memset(cost,inf,sizeof(cost)); for(int i=0;i<n;i++) rd2(point[i].x,point[i].y); for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) { int dis=point[i].distance(point[j]); if(cost[i][j]>dis) cost[i][j]=cost[j][i]=dis; } rd(m); int u,v; while(m--) { rd2(u,v); u--;v--; cost[u][v]=cost[v][u]=0; } Prim(); return 0; }I 裸的最小生成树
const int maxn=5010; int parent[110]; int n; struct Node { int from,to,edge; }node[maxn]; void init(int n) { for(int i=1;i<=n;i++) parent[i]=i; } int find(int x) { return parent[x]==x?x:find(parent[x]); } bool cmp(Node a,Node b) { if(a.edge<b.edge) return true; return false; } int main() { while(scanf("%d",&n)!=EOF) { int m=1; int len; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%d",&len); if(i<j) { int temp=m; node[temp].from=i; node[temp].to=j; node[temp].edge=len; m++; } } init(n); m=n*(n-1)/2; len=0; sort(node+1,node+1+m,cmp); for(int i=1;i<=m;i++) { int x=find(node[i].from); int y=find(node[i].to); if(x==y) continue; else { len+=node[i].edge; parent[x]=y; } } printf("%d\n",len); } return 0; }
#define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int maxn=110; const int inf=0x3f3f3f3f; int cost[maxn][maxn]; int lowc[maxn]; bool vis[maxn][maxn]; int tot; char mp[60][60]; int n,m; int dx[4]={-1,1,0,0}; int dy[4]={0,0,1,-1}; struct Point { int i,j; }point[maxn]; void BFS(int from,int x,int y) { memset(vis,0,sizeof(vis)); int step[maxn][maxn]; step[x][y]=0; vis[x][y]=1; queue<Point>q; Point a; a.i=x;a.j=y; q.push(a); while(!q.empty()) { Point first=q.front(); q.pop(); for(int i=0;i<4;i++) { int newx=first.i+dx[i]; int newy=first.j+dy[i]; if(mp[newx][newy]!='#'&&!vis[newx][newy]&&newx>=0&&newx<n&&newy>=0&&newy<m) { a.i=newx;a.j=newy; vis[newx][newy]=1; q.push(a); step[newx][newy]=step[first.i][first.j]+1; } } } for(int i=0;i<tot;i++) { cost[from][i]=step[point[i].i][point[i].j]; } } int Prime(int cost[][maxn],int n) { bool vis[maxn]; int ans=0; memset(vis,0,sizeof(vis)); vis[0]=1; for(int i=1;i<tot;i++) lowc[i]=cost[0][i]; for(int i=1;i<n;i++) { int minc=inf,p=-1; for(int j=0;j<n;j++) { if(!vis[j]&&minc>lowc[j]) { p=j; minc=lowc[j]; } } ans+=minc; vis[p]=1; for(int j=0;j<n;j++) { if(!vis[j]&&lowc[j]>cost[p][j]) lowc[j]=cost[p][j]; } } return ans; } int main() { int t;rd(t); getchar(); while(t--) { gets(mp[0]); sscanf(mp[0],"%d%d",&m,&n);//这里的格式 tot=1; for(int i=0;i<n;i++) { gets(mp[i]); int len=strlen(mp[i]); for(int k=0;k<len;k++) { if(mp[i][k]=='A') point[tot].i=i,point[tot++].j=k; else if(mp[i][k]=='S') point[0].i=i,point[0].j=k; } } //construct cost[][] memset(cost,inf,sizeof(cost)); for(int i=0;i<tot;i++) BFS(i,point[i].i,point[i].j); /* for(int i=0;i<tot;i++) { for(int j=0;j<tot;j++) cout<<cost[i][j]<<" "; cout<<endl; } */ //进行prim printf("%d\n",Prime(cost,tot)); } return 0; }
http://blog.chinaunix.net/uid-25324849-id-2182922.html
次小生成树
求最小生成树时,用maxval[i][j],表示最小生成树中i到j路径中的最大边权
求完后,直接枚举所有不在最小生成树中的边(比如该边的两端是i,j,
然后替换掉路径i,j中最大边权的边,更新答案
点的编号从0开始。
为什么可以替换、
求完最小生成树后,从i到j有路径,那么路径上的点两两可以相互到达,如果去掉最大边
,那么该路径就切成了两部分,而加入不在最小生成树的一条边(比如该边地两端是i,j)
,那么又把这两部分重新串起来了,重新变得两两可以相互到达。
#define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int maxn=110; const int inf=0x3f3f3f3f; bool vis[maxn]; int lowc[maxn]; int pre[maxn]; int cost[maxn][maxn]; int maxval[maxn][maxn]; bool used[maxn][maxn]; int Prim(int cost[][maxn],int n) { int ans=0; memset(vis,0,sizeof(vis)); memset(maxval,0,sizeof(maxval)); memset(used,0,sizeof(used)); vis[0]=true; pre[0]=-1; for(int i=1;i<n;i++) { lowc[i]=cost[0][i]; pre[i]=0; } lowc[0]=0; for(int i=1;i<n;i++) { int minc=inf,p=-1; for(int j=0;j<n;j++) { if(!vis[j]&&minc>lowc[j]) { minc=lowc[j]; p=j; } } if(minc==inf) return -1; ans+=minc; vis[p]=true; used[p][pre[p]]=used[pre[p]][p]=true; for(int j=0;j<n;j++) { if(vis[j]) maxval[j][p]=maxval[p][j]=max(maxval[j][pre[p]],lowc[p]); //为什么这么写,vis[j]代表那么节点已经访问过了,该条边是不能加的,有没有边都没关系,否则成了环, //那么在路径j->p中,j是路径的起点,p就是路径的终点,而maxval[j][pre[p]],就是起点j到p的上一个节点 //组成的路径的最大边权值,lowc[p],则是带有p的那一边的权值,二者最大值,就是路径j->p的最大权值 //比如 1->2->3->4-------->1,虚线代表有边或者没有边都行,那么此时p=4,j=1, pre[p]=3, //maxval[j][pre[p]]=maxval[1][3],也就是路径1到3上的最大边的权值,lowc[4]则是3到4上权值,二者的最大值 //则是路径1->4的最大边的权值。 if(!vis[j]&&lowc[j]>cost[p][j]) { lowc[j]=cost[p][j]; pre[j]=p; } } } return ans; } int ans;//保存最小生成树的值 int smst(int cost[][maxn],int n)//次小生成树 { int minc=inf; for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) { if(cost[i][j]!=inf&&!used[i][j])//i,j之间有边,且该边没有在最小生成树中 { minc=min(minc,ans+cost[i][j]-maxval[i][j]);//用该边替换最小生成树中i,j路径中的最大边 } } if(minc==inf) return -1; return minc; } int n,m; int main() { int t;rd(t); while(t--) { rd2(n,m); memset(cost,inf,sizeof(cost)); int u,v,w; while(m--) { rd3(u,v,w); u--; v--; if(w<cost[u][v]) cost[u][v]=cost[v][u]=w; } ans=Prim(cost,n); if(ans==smst(cost,n)) printf("Not Unique!\n"); else printf("%d\n",ans); } return 0; }
#define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int maxn=110; const int maxm=5000; struct Edge { int u,v,w; }edge[maxm]; int tot;//边的个数 int parent[maxn]; void addege(int u,int v,int w) { edge[tot].u=u; edge[tot].v=v; edge[tot++].w=w; } void init(int n) { tot=0; for(int i=0;i<=n;i++) parent[i]=i; } int find(int x) { if(parent[x]==x) return x; parent[x]=find(parent[x]); return parent[x]; } bool cmp(Edge a,Edge b) { return a.w<b.w; } int n; int kruskal(int n) { sort(edge,edge+tot,cmp); int cnt=0;//计算加入的边数 int ans=0; for(int i=0;i<tot;i++) { int u=edge[i].u; int v=edge[i].v; int w=edge[i].w; int t1=find(u); int t2=find(v); if(t1!=t2) { ans+=w; parent[t1]=t2; cnt++; } if(cnt==n-1) break; } if(cnt<n-1) return -1;//不连通 else return ans; } int main() { while(rd(n)!=EOF&&n) { init(n); int u,v,w; for(int i=1;i<=n*(n-1)/2;i++) { rd3(u,v,w); addege(u,v,w); } printf("%d\n",kruskal(n)); } return 0; }
#include <iostream> #include <stdio.h> #include <algorithm> #include <string.h> #include <stdlib.h> #include <cmath> #include <iomanip> #include <vector> #include <set> #include <map> #include <stack> #include <queue> #include <cctype> #define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; typedef long long ll; const int maxn=110; struct Point { double x,y; double distance(Point p) { return hypot(x-p.x,y-p.y); } }point[maxn]; const double inf=100000.0; bool vis[maxn]; double lowc[maxn]; double cost[maxn][maxn]; double Prim(double cost[][maxn],int n) { double ans=0; memset(vis,0,sizeof(vis)); vis[0]=true; for(int i=1;i<n;i++) lowc[i]=cost[0][i]; for(int i=1;i<n;i++) { double minc=inf; int p=-1; for(int j=0;j<n;j++) { if(!vis[j]&&minc>lowc[j]) { minc=lowc[j]; p=j; } } if(minc==inf) return -1.0; ans+=minc; vis[p]=true; for(int j=0;j<n;j++) if(!vis[j]&&lowc[j]>cost[p][j]) lowc[j]=cost[p][j]; } return ans; } int n; int main() { int t;rd(t); while(t--) { rd(n); for(int i=0;i<n;i++) scanf("%lf%lf",&point[i].x,&point[i].y); for(int i=0;i<n;i++) { for(int j=0;j<n;j++) cost[i][j]=inf; } /* for(int i=0;i<n;i++) { for(int j=0;j<n;j++) cout<<cost[i][j]<<" "; cout<<endl; } */ for(int i=0;i<n;i++) { for(int j=i+1;j<n;j++) { double dis=point[i].distance(point[j]); if(dis<cost[i][j]&&dis>=10&&dis<=1000) { cost[i][j]=dis; cost[j][i]=dis; } } } double ans=Prim(cost,n); if(ans==-1.0) printf("oh!\n"); else printf("%.1f\n",ans*100); } return 0; }