机试真题重点题目-2016
C:架线方案
考察:最小生成树
Prim解决:

#include <iostream> #include <cstring> using namespace std; const int N = 1010, INF = 0x3f3f3f3f; int k, n, m; //k组数,n个城市,m条线 int g[N][N]; int dist[N]; bool st[N]; int prim() { memset(dist, 0x3f, sizeof dist); memset(st, false, sizeof st); int res = 0; for(int i = 0; i<n; i++) { int t = -1; for(int j = 0; j<n; j++) { if(!st[j] && (t == -1 || dist[t] > dist[j])) t = j; } st[t] = true; if(i && dist[t] == INF) return INF; if(i) res += dist[t]; for(int j = 0; j<n; j++) dist[j] = min(dist[j], g[t][j]); } return res; } int main() { memset(g, 0x3f, sizeof g); cin >> k; while(k --) { cin >> n >> m; while(m --) { int a, b, c; cin >> a >> b >> c; g[a][b] = g[b][a] = min(g[a][b], c); } int res = prim(); if(res == INF) cout << -1 << endl; else cout << res << endl; memset(g, 0x3f, sizeof g); //下一组数据开始前要初始化 } return 0; } /* 1 3 3 0 1 1 2 1 2 2 0 1 输出:2 */
Kruskal解决:

#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 10010, M = 20010; int p[N]; //并查集 int k, n, m; struct Edge { int a, b, w; }edges[M]; bool cmp(Edge a, Edge b) { return a.w < b.w; } void InitUnionSet() { for(int i = 0; i<n; i++) p[i] = i; return; } //找集合根结点 int find(int x) { if(p[x] != x) p[x] = find(p[x]); return p[x]; } int kruskal() { sort(edges, edges + n, cmp); int res = 0, cnt = 0; //权值,边数 for(int i = 0; i<m; i++) { int a = edges[i].a; int b = edges[i].b; int w = edges[i].w; a = find(a), b = find(b); if(a != b) { p[a] = p[b]; cnt ++; res += w; } } if(cnt < n - 1) return -1; //少于n-1条边构不成最小生成树 else return res; } int main() { cin >> k; while(k --){ cin >> n >> m; InitUnionSet(); for(int i = 0; i<m; i++) { int a, b, c; cin >> a >> b >> c; edges[i] = {a, b, c}; } int t = kruskal(); if(t == -1) cout << -1 << endl; else cout << t << endl; } return 0; } /* 1 3 3 0 1 1 2 1 2 2 0 1 输出:2 */
D:搬箱子
考察:线性DP
本质:最长上升子序列

#include <iostream> using namespace std; const int N = 510; int a[N], f[N]; //f[i]:以a[i]为结尾的序列长度 int n; int main() { cin >> n; for(int i = 1; i<=n; i++) cin >> a[i]; for(int i = 1; i<=n; i++) { f[i] = 1; for(int j = 1; j<i; j++) { if(a[j] < a[i]) f[i] = max(f[i], f[j] + 1); } } int res = 0; for(int i = 1; i<=n; i++) res = max(res, f[i]); cout << res << endl; return 0; } /* 7 1 7 3 5 4 9 8 输出:4 */
E:树的高度
考察:DFS

#include <iostream> #include <cstring> using namespace std; const int N = 10010, M = 20010;//无向图边是顶点两倍 int n, root; int h[N], e[M], ne[M], idx; int dist[N]; void add(int a, int b) { e[idx] = b; ne[idx] = h[a]; h[a] = idx++; } void dfs(int u, int fa) { for(int i = h[u]; i != -1; i = ne[i]) { //取出与u相连的结点 int j = e[i]; //可能是u的父结点,直接跳过 if(j == fa) continue; dist[j] = dist[u] + 1; dfs(j, u);//以j为新结点,u为父结点继续深搜 } } int main() { memset(h, -1, sizeof h); memset(dist, 0, sizeof dist); cin >> n >> root; for(int i = 0; i<n-1; i++) { int a, b; cin >> a >> b; add(a, b), add(b, a); } dfs(root, -1); int res = 0; for(int i = 1; i<=n; i++) res = max(res, dist[i]); cout << res << endl; return 0; } /* 5 5 1 2 1 4 1 5 2 3 输出:3 */