HDU1102 Constructing Roads —— 最小生成树

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1102


题解:

纯最小生成树,只是有些边已经确定了要加入生成树中,特殊处理一下这些边就可以了。


kruskal算法:

由于有些边已经确定,所以在调用kruskal()之前,就把这条边的两个顶点放在一个集合就可以了。

 1 #include<cstdio>//hdu1102 最小生成树 kruskal
 2 #include<algorithm>
 3 #define N 110
 4 using namespace std;
 5 
 6 struct node
 7 {
 8     int x,y,dis;
 9 }edge[N*N];
10 
11 int fa[N];
12 
13 bool cmp(node a, node b)
14 {
15     return a.dis<=b.dis;
16 }
17 
18 int find(int x)
19 {
20     return fa[x]==x?x:find(fa[x]);
21 }
22 
23 bool un(int x, int y)
24 {
25     x = find(x);
26     y = find(y);
27     if(x!=y)
28     {
29         fa[x] = y;
30         return true;
31     }
32     return false;
33 }
34 
35 int kruskal(int n,int sum)
36 {
37     int len = 0,x,y,i;
38     sort(edge,edge+sum,cmp);
39     for(i = 0; i<sum; i++)
40     {
41         x = edge[i].x;
42         y = edge[i].y;
43         if(un(x,y))
44             len += edge[i].dis;
45     }
46     return len;
47 }
48 
49 int main()
50 {
51     int n,m,i,j,x,y,dis,sum;
52     while(scanf("%d",&n)!=EOF)
53     {
54         sum = 0;
55         for(i = 1; i<=n; i++)
56         for(j = 1; j<=n; j++)
57         {
58             scanf("%d",&dis);
59             if(i>=j) continue;
60             edge[sum].x = i;
61             edge[sum].y = j;
62             edge[sum].dis = dis;
63             sum++;
64         }
65 
66         for(i = 1; i<=n; i++)
67             fa[i] = i;
68 
69         scanf("%d",&m);
70         for(i = 0; i<m; i++)//先处理以确定的边
71         {
72             scanf("%d%d",&x,&y);
73             un(x,y);
74         }
75         printf("%d\n",kruskal(n,sum));
76     }
77    return 0;
78 }
View Code

 

prim算法:

在prim算法中就不能像kruskal算法那样先预处理了,而要在算法中运行。由于prim算法在每次松弛时总是找最小的点,题目中两条村庄的距离是非负数,那么我们可以把确定要加入生成树的边的两个顶点的距离设为-1,这样就能确保他们都加入到生成树中了。

注意:赋值或修改邻接矩阵的无向图时, 正反两条边都要操作。

 1 #include<cstdio>//hdu1102 最小生成树 prim
 2 #include<algorithm>
 3 #define N 110
 4 #define INF  0x7fffffff
 5 using namespace std;
 6 
 7 int arc[N][N];
 8 
 9 int prim(int n)
10 {
11     int low[N];
12     int k,i,j,min,len = 0;
13     for(i = 1; i<=n; i++)
14     {
15         low[i] = arc[1][i];
16     }
17 
18     for(i = 2; i<=n; i++)
19     {
20         min = INF;
21         for(j = 2; j<=n; j++)
22         {
23             if(low[j]!=0 && low[j]<min)
24             {
25                 min = low[j];
26                 k = j;
27             }
28         }
29 
30         if(low[k]>0)
31             len += low[k];
32         low[k] = 0;
33 
34         for(int j = 2; j<=n; j++)
35         {
36             if(low[j]!=0 && arc[k][j]<low[j])
37             {
38                 low[j] = arc[k][j];
39             }
40         }
41     }
42     return len;
43 }
44 
45 int main()
46 {
47     int n,q,u,v,i,j;
48     while(scanf("%d",&n)!=EOF)
49     {
50         for(i = 1; i<=n; i++)
51         for(j = 1; j<=n; j++)
52             scanf("%d",&arc[i][j]);
53 
54         scanf("%d",&q);
55         for(i = 0; i<q; i++)
56         {
57             scanf("%d%d",&u,&v);
58             arc[v][u] = arc[u][v] = -1;
59             //正反向都要置为-1, 因为在松弛的过程中,两个方向都有可能
60         }
61         printf("%d\n",prim(n));
62     }
63    return 0;
64 }
View Code

 


 

posted on 2017-03-24 20:03  h_z_cong  阅读(155)  评论(0编辑  收藏  举报

导航