题目http://acm.hdu.edu.cn/showproblem.php?pid=1879
复习一下最小生成树的两个基本算法。
由于存在道路是否已修建的问题,如果已修建,那么该条道路的成本即为0.
首先复习一下kruskal,它的思路主要是既然有那么多边,那么多权值(这里即为成本),要求全连通后最小的权值,那么就将权值排序,先从最小的权值看起,
将该权值的对应的两点用并查集合并到一个集合里,然后依次按照权值从小到大的顺序比较下去,如果该权值对应的两点的祖先结点相同,证明这两点已经
连通,如果祖先结点不同,那么证明不在同一个集合里,这两点没连通,那么连通这两点(合并并查集),加上该权值~~。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 #define M 5005 5 int father[M],r[M]; 6 int a[M],b[M],c[M],d[M]; 7 bool cmp(int i,int j) {return c[i]<c[j];} 8 int find(int x){ 9 if (x==father[x]) return x; 10 father[x]=find(father[x]); 11 return father[x]; 12 } 13 int kruska(int n){ 14 int i,ans=0; 15 for (i=1;i<=n;i++) father[i]=r[i]=i; 16 sort(r+1,r+n+1,cmp);、//看懂这个排序,将数组r以数组c从小到大的顺序排,其实就是个结构体 17 for (i=1;i<=n;i++){ 18 int e=r[i]; 19 int sx=find(a[e]); 20 int sy=find(b[e]); 21 if (sx!=sy){ 22 ans+=c[e];father[sx]=sy; 23 } 24 } 25 return ans; 26 } 27 int main() 28 { 29 int n,i; 30 while (~scanf("%d",&n)&&n){ 31 for (i=1;i<=n*(n-1)/2;i++){ 32 scanf("%d %d %d %d",&a[i],&b[i],&c[i],&d[i]); 33 if (d[i]) c[i]=0; 34 } 35 printf("%d ",kruska(n*(n-1)/2)); 36 } 37 return 0; 38 }
然后是prime,它是从某个顶点开始将它加入一个集合中,然后将集合内的顶点与集合外的顶点所构成的所有边中选取权值最小的一条边作为生成树的边,
并将集合外的那个顶点加入到集合中,表示该顶点已连通,然后再用集合内的顶点与集合外的顶点构成的边中找最小的边,并将相应的顶点加入集合中,这样下去直到全部顶点都加入到集合中,
即得最小生成树.
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 #define M 5005 5 #define inf 0x3f3f3f3f 6 int a[M],b[M],c[M],d[M]; 7 int dis[111],vis[111],mapp[111][111]; 8 int prime(int n){ 9 int ans=0,i,j; 10 for (i=2;i<=n;i++) dis[i]=mapp[1][i]; 11 memset(vis,0,sizeof(vis)); 12 vis[1]=1; 13 for (i=1;i<n;i++){ 14 int temp=inf,pos; 15 for (j=1;j<=n;j++){//dis数组表示集合内与集合外的点的最小权值, 16 if (!vis[j]&&temp>dis[j]) 17 pos=j,temp=dis[j]; 18 } 19 ans+=dis[pos]; 20 vis[pos]=1; 21 for (j=1;j<=n;j++){ 22 if (!vis[j]&&dis[j]>mapp[pos][j])、、更新一遍dis 23 dis[j]=mapp[pos][j]; 24 } 25 } 26 return ans; 27 } 28 int main() 29 { 30 int n,i,j; 31 while (~scanf("%d",&n)&&n){ 32 for (i=1;i<=n;i++) 33 for (j=1;j<=n;j++) 34 mapp[i][j]=inf; 35 for (i=1;i<=n*(n-1)/2;i++){ 36 scanf("%d %d %d %d",&a[i],&b[i],&c[i],&d[i]); 37 if (d[i]) c[i]=0; 38 mapp[a[i]][b[i]]=mapp[b[i]][a[i]]=c[i]; 39 } 40 printf("%d ",prime(n)); 41 } 42 return 0; 43 }