程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 最小生成樹,POJ和HDU幾道題目的解題報告(基於自己寫的模板)

最小生成樹,POJ和HDU幾道題目的解題報告(基於自己寫的模板)

編輯:C++入門知識

首先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 }

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved