机试真题重点题目-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 
*/
View Code

 

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 
*/
View Code

 

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 
*/
View Code

 

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 
*/
View Code

 

posted @ 2024-03-20 18:26  GeekDragon  阅读(1)  评论(0编辑  收藏  举报