首先POJ題目:
鏈接:1251 Jungle Roads
題目大意:純求最小生成樹,結果為最小權值邊的和。采用鄰接表
代碼:
1 #include <iostream>
2 #include <cstdio>
3 #include <vector>
4 #include <queue>
5 using namespace std;
6
7 #define maxn 30 //最大頂點個數
8 int n; //頂點數,邊數
9
10 struct arcnode //邊結點
11 {
12 int vertex; //與表頭結點相鄰的頂點編號
13 int weight; //連接兩頂點的邊的權值
14 arcnode * next; //指向下一相鄰接點
15 arcnode() {}
16 arcnode(int v,int w):vertex(v),weight(w),next(NULL) {}
17 };
18
19 struct vernode //頂點結點,為每一條鄰接表的表頭結點
20 {
21 int vex; //當前定點編號
22 arcnode * firarc; //與該頂點相連的第一個頂點組成的邊
23 }Ver[maxn];
24
25 void Init() //建立圖的鄰接表需要先初始化,建立頂點結點
26 {
27 for(int i = 1; i <= n; i++)
28 {
29 Ver[i].vex = i;
30 Ver[i].firarc = NULL;
31 }
32 }
33
34 void Insert(int a, int b, int w) //頭插法,效率更高,但不能去重邊
35 {
36 arcnode * q = new arcnode(b, w);
37 if(Ver[a].firarc == NULL)
38 Ver[a].firarc = q;
39 else
40 {
41 arcnode * p = Ver[a].firarc;
42 q->next = p;
43 Ver[a].firarc = q;
44 }
45 }
46 struct node //保存key值的結點
47 {
48 int v;
49 int key;
50 friend bool operator<(node a, node b) //自定義優先級,key小的優先
51 {
52 return a.key > b.key;
53 }
54 };
55
56 #define INF 0xfffff //權值上限
57 int parent[maxn]; //每個結點的父節點
58 bool visited[maxn]; //是否已經加入樹種
59 node vx[maxn]; //保存每個結點與其父節點連接邊的權值
60 priority_queue<node> q; //優先隊列stl實現
61 void Prim(int s) //s表示根結點
62 {
63 for(int i = 1; i <= n; i++) //初始化
64 {
65 vx[i].v = i;
66 vx[i].key = INF;
67 parent[i] = -1;
68 visited[i] = false;
69 }
70 vx[s].key = 0;
71 q.push(vx[s]);
72 while(!q.empty())
73 {
74 node nd = q.top(); //取隊首,記得趕緊pop掉
75 visited[nd.v] = true;
76 q.pop();
77 arcnode * p = Ver[nd.v].firarc;
78 while(p != NULL) //找到所有相鄰結點,若未訪問,則入隊列
79 {
80 if(!visited[p->vertex] && p->weight < vx[p->vertex].key)
81 {
82 parent[p->vertex] = nd.v;
83 vx[p->vertex].key = p->weight;
84 vx[p->vertex].v = p->vertex;
85 q.push(vx[p->vertex]);
86 }
87 p = p->next;
88 }
89 }
90 }
91 void Show() //打印圖的鄰接表(有權值)
92 {
93 for(int i = 1; i <= n; i++)
94 {
95 cout << Ver[i].vex;
96 arcnode * p = Ver[i].firarc;
97 while(p != NULL)
98 {
99 cout << "->(" << p->vertex << "," << p->weight << ")";
100 p = p->next;
101 }
102 cout << "->NULL" << endl;
103 }
104 }
105 int main()
106 {
107 int k, d;
108 char x, y;
109 while(cin >> n && n!=0)
110 {
111 Init();
112 for(int i = 1; i < n; i++)
113 {
114 cin >> x >> k;
115 while(k--)
116 {
117 cin >> y >> d;
118 Insert(x-'A'+1, y-'A'+1, d);
119 Insert(y-'A'+1, x-'A'+1, d);
120 }
121 }
122 Prim(1);
123 int ans = 0;
124 for(int i = 1; i <= n; i++)
125 ans += vx[i].key;
126 printf("%d\n", ans);
127 }
128 return 0;
129 }
鏈接:1258 Agri-Net
題目大意:求最小生成樹,鄰接矩陣實現
1 #include <iostream>
2 #include <cstdio>
3 #include <queue>
4 using namespace std;
5
6 #define maxn 110
7 #define INF 100020 //預定於的最大值
8 int n; //頂點數、邊數
9 int g[maxn][maxn]; //鄰接矩陣表示
10
11 struct node //保存key值的結點
12 {
13 int v;
14 int key;
15 friend bool operator<(node a, node b) //自定義優先級,key小的優先
16 {
17 return a.key > b.key;
18 }
19 };
20 int parent[maxn]; //每個結點的父節點
21 bool visited[maxn]; //是否已經加入樹種
22 node vx[maxn]; //保存每個結點與其父節點連接邊的權值
23 priority_queue<node> q; //優先隊列stl實現
24 void Prim(int s) //s表示根結點
25 {
26 for(int i = 1; i <= n; i++) //初始化
27 {
28 vx[i].v = i;
29 vx[i].key = INF;
30 parent[i] = -1;
31 visited[i] = false;
32 }
33 vx[s].key = 0;
34 q.push(vx[s]);
35 while(!q.empty())
36 {
37 node nd = q.top(); //取隊首,記得趕緊pop掉
38 q.pop();
39 if(visited[nd.v] == true) //深意,因為push機器的可能是重復但是權值不同的點,我們只取最小的
40 continue;
41 int st = nd.v;
42 //cout << nd.v << " " << nd.key << endl;
43 visited[nd.v] = true;
44 for(int j = 1; j <= n; j++)
45 {
46 if(j!=st && !visited[j] && g[st][j] < vx[j].key) //判斷
47 {
48 parent[j] = st;
49 vx[j].key = g[st][j];
50 q.push(vx[j]);
51
52 }
53 }
54 }
55 }
56 int main()
57 {
58 while(~scanf("%d", &n))
59 {
60 for(int i = 1; i <= n; i++)
61 for(int j = 1; j <= n; j++)
62 {
63 scanf("%d", &g[i][j]);
64 if(g[i][j] == 0)
65 g[i][j] = INF;
66 }
67 Prim(1);
68 int ans = 0;
69 for(int i = 1; i <= n; i++)
70 ans += vx[i].key;
71 printf("%d\n", ans);
72
73 }
74 return 0;
75 }
鏈接:1789 Truck History
題目大意:n種卡車,互相之間的差別為同一位置上不同字母的個數,這相當於每個點的權值,根據這個權值來求最小生成樹。
代碼,采用鄰接矩陣:
1 #include <iostream>
2 #include <cstdio>
3 #include <queue>
4 using namespace std;
5
6 #define maxn 2020
7 #define INF 10 //預定於的最大值
8 int n; //頂點數、邊數
9 int g[maxn][maxn]; //鄰接矩陣表示
10
11 struct node //保存key值的結點
12 {
13 int v;
14 int key;
15 friend bool operator<(node a, node b) //自定義優先級,key小的優先
16 {
17 return a.key > b.key;
18 }
19 };
20 bool visited[maxn]; //是否已經加入樹種
21 node vx[maxn]; //保存每個結點與其父節點連接邊的權值
22 priority_queue<node> q; //優先隊列stl實現
23 void Prim(int s) //s表示根結點
24 {
25 for(int i = 1; i <= n; i++) //初始化
26 {
27 vx[i].v = i;
28 vx[i].key = INF;
29 visited[i] = false;
30 }
31 vx[s].key = 0;
32 q.push(vx[s]);
33 while(!q.empty())
34 {
35 node nd = q.top(); //取隊首,記得趕緊pop掉
36 q.pop();
37 if(visited[nd.v] == true) //深意,因為push機器的可能是重復但是權值不同的點,我們只取最小的
38 continue;
39 int st = nd.v;
40 visited[nd.v] = true;
41 for(int j = 1; j <= n; j++)
42 {
43 if(j!=st && !visited[j] && g[st][j] < vx[j].key) //判斷
44 {
45 vx[j].key = g[st][j];
46 q.push(vx[j]);
47 }
48 }
49 }
50 }
51 char tk[2020][8];
52 int main()
53 {
54 while(scanf("%d", &n), n)
55 {
56 for(int i = 1; i <= n; i++)
57 scanf("%s", tk[i]);
58 for(int i = 1; i < n; i++)
59 {
60 for(int j = i+1; j <= n; j++)
61 {
62 int cnt = 0;
63 for(int k = 0; k < 7; k++)
64 if(tk[i][k] != tk[j][k])
65 cnt++;
66 g[i][j] = g[j][i] = cnt;
67 }
68 }
69 Prim(1);
70 int ans = 0;
71 for(int i = 1; i <= n; i++)
72 ans += vx[i].key;
73 printf("The highest possible quality is 1/%d.\n", ans);
74 }
75 return 0;
76 }
鏈接:2485 Highways
題目大意:依然是最小生成樹,輸出權值最大的邊。
代碼:
1 #include <iostream>
2 #include <cstdio>
3 #include <queue>
4 using namespace std;
5
6 #define maxn 510
7 #define INF 0xffffff //預定於的最大值
8 int n; //頂點數、邊數
9 int g[maxn][maxn]; //鄰接矩陣表示
10
11 struct node //保存key值的結點
12 {
13 int v;
14 int key;
15 friend bool operator<(node a, node b) //自定義優先級,key小的優先
16 {
17 return a.key > b.key;
18 }
19 };
20 bool visited[maxn]; //是否已經加入樹中
21 node vx[maxn]; //保存每個結點與其父節點連接邊的權值
22 priority_queue<node> q; //優先隊列stl實現
23 void Prim(int s) //s表示根結點
24 {
25 for(int i = 1; i <= n; i++) //初始化
26 {
27 vx[i].v = i;
28 vx[i].key = INF;
29 visited[i] = false;
30 }
31 vx[s].key = 0;
32 q.push(vx[s]);
33 while(!q.empty())
34 {
35 node nd = q.top(); //取隊首,記得趕緊pop掉
36 q.pop();
37 if(visited[nd.v] == true) //深意,因為push機器的可能是重復但是權值不同的點,我們只取最小的
38 continue;
39 int st = nd.v;
40 visited[nd.v] = true;
41 for(int j = 1; j <= n; j++)
42 {
43 if(j!=st && !visited[j] && g[st][j] < vx[j].key) //判斷
44 {
45 vx[j].key = g[st][j];
46 q.push(vx[j]);
47 }
48 }
49 }
50 }
51 int main()
52 {
53 int t;
54 scanf("%d", &t);
55 while(t--)
56 {
57 scanf("%d", &n);
58 for(int i = 1; i <= n; i++)
59 {
60 for(int j = 1; j <= n; j++)
61 scanf("%d", &g[i][j]);
62 g[i][i] = INF;
63 }
64 Prim(1);
65 int ans = 0;
66 for(int i = 1; i <= n; i++)
67 if(vx[i].key > ans)
68 ans = vx[i].key;
69 printf("%d\n", ans);
70
71 }
72 return 0;
73 }
HDOJ
鏈接:1863 暢通工程
題目大意:求全省暢通最低成本,最小生成樹,判斷能否生成一棵樹,如果能輸出最小代價,不能輸出 ?
代碼,采用鄰接表:
1 #include <iostream>
2 #include <cstdio>
3 #include <queue>
4 using namespace std;
5
6 #define maxn 110 //最大頂點個數
7 int n, m; //頂點數,邊數
8
9 struct arcnode //邊結點
10 {
11 int vertex; //與表頭結點相鄰的頂點編號
12 int weight; //連接兩頂點的邊的權值
13 arcnode * next; //指向下一相鄰接點
14 arcnode() {}
15 arcnode(int v,int w):vertex(v),weight(w),next(NULL) {}
16 };
17
18 struct vernode //頂點結點,為每一條鄰接表的表頭結點
19 {
20 int vex; //當前定點編號
21 arcnode * firarc; //與該頂點相連的第一個頂點組成的邊
22 }Ver[maxn];
23
24 void Init() //建立圖的鄰接表需要先初始化,建立頂點結點
25 {
26 for(int i = 1; i <= n; i++)
27 {
28 Ver[i].vex = i;
29 Ver[i].firarc = NULL;
30 }
31 }
32
33 void Insert(int a, int b, int w) //頭插法,效率更高,但不能去重邊
34 {
35 arcnode * q = new arcnode(b, w);
36 if(Ver[a].firarc == NULL)
37 Ver[a].firarc = q;
38 else
39 {
40 arcnode * p = Ver[a].firarc;
41 q->next = p;
42 Ver[a].firarc = q;
43 }
44 }
45
46 struct node //保存key值的結點
47 {
48 int v;
49 int key;
50 friend bool operator<(node a, node b) //自定義優先級,key小的優先
51 {
52 return a.key > b.key;
53 }
54 };
55
56 #define INF 999999999 //權值上限
57 int parent[maxn]; //每個結點的父節點
58 bool visited[maxn]; //是否已經加入樹種
59 node vx[maxn]; //保存每個結點與其父節點連接邊的權值
60 priority_queue<node> q; //優先隊列stl實現
61 void Prim(int s) //s表示根結點
62 {
63 for(int i = 1; i <= n; i++) //初始化
64 {
65 vx[i].v = i;
66 vx[i].key = INF;
67 parent[i] = -1;
68 visited[i] = false;
69 }
70 vx[s].key = 0;
71 q.push(vx[s]);
72 while(!q.empty())
73 {
74 node nd = q.top(); //取隊首,記得趕緊pop掉
75 q.pop();
76 if(visited[nd.v] == true)
77 continue;
78 visited[nd.v] = true;
79 arcnode * p = Ver[nd.v].firarc;
80 while(p != NULL) //找到所有相鄰結點,若未訪問,則入隊列
81 {
82 if(!visited[p->vertex] && p->weight < vx[p->vertex].key)
83 {
84 parent[p->vertex] = nd.v;
85 vx[p->vertex].key = p->weight;
86 vx[p->vertex].v = p->vertex;
87 q.push(vx[p->vertex]);
88 }
89 p = p->next;
90 }
91 }
92 }
93 int main()
94 {
95 int a, b, w;
96 while(scanf("%d%d", &m, &n), m)
97 {
98 Init();
99 while(m--)
100 {
101 scanf("%d%d%d", &a, &b, &w);
102 if(a != b)
103 {
104 Insert(a, b, w);
105 Insert(b, a, w);
106 }
107 }
108 Prim(1);
109 int cnt = 0, ans = 0;
110 for(int i = 1; i <= n; i++)
111 {
112 if(parent[i] == -1)
113 cnt++;
114 ans += vx[i].key;
115 }
116 if(cnt >= 2)
117 printf("?\n");
118 else
119 printf("%d\n", ans);
120
121 }
122 return 0;
123 }
鏈接:1875 暢通工程再續
題目大意:依然是最小生成樹,但是點換成了坐標表示,權值表示為兩點的距離,求最小權值的和。
代碼,鄰接表:
1 #include <iostream>
2 #include <cstdio>
3 #include <cmath>
4 #include <queue>
5 using namespace std;
6
7 #define maxn 110 //最大頂點個數
8 int n; //頂點數,邊數
9
10 struct arcnode //邊結點
11 {
12 int vertex; //與表頭結點相鄰的頂點編號
13 double weight; //連接兩頂點的邊的權值
14 arcnode * next; //指向下一相鄰接點
15 arcnode() {}
16 arcnode(int v,double w):vertex(v),weight(w),next(NULL) {}
17 };
18
19 struct vernode //頂點結點,為每一條鄰接表的表頭結點
20 {
21 int vex; //當前定點編號
22 arcnode * firarc; //與該頂點相連的第一個頂點組成的邊
23 }Ver[maxn];
24
25 void Init() //建立圖的鄰接表需要先初始化,建立頂點結點
26 {
27 for(int i = 1; i <= n; i++)
28 {
29 Ver[i].vex = i;
30 Ver[i].firarc = NULL;
31 }
32 }
33
34 void Insert(int a, int b, double w) //尾插法,插入以a為起點,b為終點,權為w的邊,效率不如頭插,但是可以去重邊
35 {
36 arcnode * q = new arcnode(b, w);
37 if(Ver[a].firarc == NULL)
38 Ver[a].firarc = q;
39 else
40 {
41 arcnode * p = Ver[a].firarc;
42 q->next = p;
43 Ver[a].firarc = q;
44 }
45 }
46
47 struct node //保存key值的結點
48 {
49 int v;
50 double key;
51 friend bool operator<(node a, node b) //自定義優先級,key小的優先
52 {
53 return a.key > b.key;
54 }
55 };
56
57 #define INF 1e10 //權值上限
58 #define eps 1e-9
59 int parent[maxn]; //每個結點的父節點
60 bool visited[maxn]; //是否已經加入樹種
61 node vx[maxn]; //保存每個結點與其父節點連接邊的權值
62 priority_queue<node> q; //優先隊列stl實現
63 void Prim(int s) //s表示根結點
64 {
65 for(int i = 1; i <= n; i++) //初始化
66 {
67 vx[i].v = i;
68 vx[i].key = INF;
69 parent[i] = -1;
70 visited[i] = false;
71 }
72 vx[s].key = 0;
73 q.push(vx[s]);
74 while(!q.empty())
75 {
76 node nd = q.top(); //取隊首,記得趕緊pop掉
77 q.pop();
78 if(visited[nd.v] == true)
79 continue;
80 visited[nd.v] = true;
81 arcnode * p = Ver[nd.v].firarc;
82 while(p != NULL) //找到所有相鄰結點,若未訪問,則入隊列
83 {
84 if(!visited[p->vertex] && p->weight < vx[p->vertex].key)
85 {
86 parent[p->vertex] = nd.v;
87 vx[p->vertex].key = p->weight;
88 vx[p->vertex].v = p->vertex;
89 q.push(vx[p->vertex]);
90 }
91 p = p->next;
92 }
93 }
94 }
95 void Show() //打印圖的鄰接表(有權值)
96 {
97 for(int i = 1; i <= n; i++)
98 {
99 cout << Ver[i].vex;
100 arcnode * p = Ver[i].firarc;
101 while(p != NULL)
102 {
103 cout << "->(" << p->vertex << "," << p->weight << ")";
104 p = p->next;
105 }
106 cout << "->NULL" << endl;
107 }
108 }
109 struct Point
110 {
111 int x, y;
112 }PT[maxn];
113 double dis(Point p1, Point p2)
114 {
115 return 100.0*sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
116 }
117 int main()
118 {
119 int t;
120 scanf("%d", &t);
121 while(t--)
122 {
123 scanf("%d", &n);
124 for(int i = 1; i <= n; i++)
125 scanf("%d%d", &PT[i].x, &PT[i].y);
126 Init();
127 for(int i = 1; i < n; i++)
128 for(int j = i+1; j <= n; j++)
129 {
130 double d = dis(PT[i], PT[j]);
131 if(1000.00 - d > eps || d -100000.00 > eps)
132 continue;
133 Insert(i, j, d);
134 Insert(j, i, d);
135 }
136 Prim(1);
137 int cnt = 0;
138 double ans = 0;
139 for(int i = 1; i <= n; i++)
140 {
141 if(parent[i] == -1)
142 cnt++;
143 ans += vx[i].key;
144 if(cnt == 2)
145 break;
146 }
147 if(cnt == 2)
148 printf("oh!\n");
149 else
150 printf("%.1lf\n", ans);
151 }
152 return 0;
153 }
鏈接:1879
題目大意:這道題問題在於其中有些邊已經存在,即有些路已經被修建好了,我們只需要將已經建好的邊的權值置為0就必定會加入到最小生成樹中
問題:這道題用Prim暫時還沒過,應該是有什麼坑數據,還在鑽研
下面貼Kruskal的代碼:
1 #include <iostream>
2 #include <cstdio>
3 #include <algorithm>
4 using namespace std;
5
6 #define maxn 110
7 struct eage
8 {
9 int u, v, w;
10 }EG[5050];
11 int parent[maxn];
12 int n, m;
13 bool cmp(eage a, eage b)
14 {
15 return a.w < b.w;
16 }
17 int Find(int x)
18 {
19 if(parent[x] == -1) return x;
20 return Find(parent[x]);
21 }
22 void Kruskal()
23 {
24 for(int i = 1; i <= n; i++)
25 parent[i] = -1;
26 sort(EG+1, EG+m+1, cmp);
27 int ans = 0;
28 for(int i = 1; i <= m; i++)
29 {
30 int x = Find(EG[i].u);
31 int y = Find(EG[i].v);
32 if(x != y)
33 {
34 ans += EG[i].w;
35 parent[x] = y;
36 }
37 }
38 printf("%d\n", ans);
39 }
40 int main()
41 {
42 int w, f;
43 while(scanf("%d", &n), n)
44 {
45 m = n*(n-1)/2;
46 for(int i = 1; i <= m; i++)
47 {
48 scanf("%d%d%d%d", &EG[i].u, &EG[i].v, &w, &f);
49 if(f == 1)
50 w = 0;
51 EG[i].w = w;
52 }
53 Kruskal();
54 }
55 return 0;
56 }