中南大学研究生复试机试题

题目不全,不分先后

1 惠民工程

题目描述

市政府“惠民工程”的目标是在全市n个居民点间之架设煤气管道(但不一定有直接的管道相连,只要能间接通过管道可达即可)。很显然最多可架设 n(n-1)/2条管道,然而实际上要连通n个居民点只需架设n-1条管道就可以了。现请你编写程序,计算出该惠民工程需要的最低成本。

输入

测试输入包含若干测试用例。每个测试用例的第1行给出居民点数目M ( < =100 )、 评估的管道条数 N;随后的 N 行对应居民点间管道的成本,每行给出一对正整数,分别是两个居民点的编号,以及此两居民点间管道的成本(也是正整数)。为简单起见,居民点从1到M编号。

输出

对每个测试用例,在1行里输出全市管道畅通所需要的最低成本。若统计数据不足以保证畅通,则输出“?”。

样例输入

3 3
1 2 1
1 3 2
2 3 4
3 1
2 3 2

样例输出

3
?

代码

#使用并查集的Kruskal算法
#include <iostream>
#include <algorithm>
#define MAX 110
#define MAXN 100010
 
using namespace std;
 
int n, m, INF = 0x3f3f3f3f;
int fa[MAX];
 
struct edge {
    int a, b, c;
    bool operator< (const edge& e) const {
        return c < e.c;
    }
} edge[MAXN];
 
int find (int x) {
    return ((fa[x] == x) ? x : find(fa[x]));
}
 
int kruskal () {
    sort(edge, edge + n);
     
    for (int i = 1; i <= m; i ++) fa[i] = i;
     
    int res = 0, cnt = 0;
    for (int i = 0; i < n; i ++) {
        int a = edge[i].a, b = edge[i].b, c = edge[i].c;
         
        a = find(a), b = find(b);
        if (a != b) {
            fa[a] = b;
            res += c;
            cnt ++;
        }
    }
     
    if (cnt < m - 1) return INF;
    return res;
} 
 
int main () {
    while (cin >> m >> n) {
        for (int i = 0; i < n; i ++) {
            cin >> edge[i].a >> edge[i].b >> edge[i].c;
        }
        int res = kruskal();
         
        if (res == INF) cout << "?" << endl;
        else cout << res << endl;
    }
    return 0;
}

2 回文串问题

题目描述

“回文串”是一个正读和反读都一样的字符串,字符串由数字和小写字母组成,比如“level”或者“abcdcba”等等就是回文串。请写一个程序判断读入的字符串是否是“回文”。

输入

输入包含多个测试实例,每一行对应一个字符串,串长最多100字母。

输出

对每个字符串,输出它是第几个,如第一个输出为"case1: “;如果一个字符串是回文串,则输出"yes”,否则输出"no",在yes/no之前用一个空格。

样例输入

level
abcde
noon
haha

样例输出

case1: yes
case2: no
case3: yes
case4: no

代码

#动态规划
#include <iostream>
#include <cstdio>
#include <cstring>
#define MAX 110
 
using namespace std;
 
string s;
int f[MAX][MAX];
 
int main () {
     
    int cnt = 1;
    while (cin >> s) {
        memset(f, 1, sizeof f);
        int n = s.size();
        for (int i = n - 1; i >= 0; i --) {
            for (int j = i + 1; j < n; j ++) {
                f[i][j] = (s[i] == s[j]) && f[i + 1][j - 1];
            }
        }
         
        if (f[0][n - 1]) {
            printf("case%d: yes\n", cnt);
        } else {
            printf("case%d: no\n", cnt);
        }
         
        cnt ++;
    }
     
    return 0;
} 

3 最少钱币数

题目描述

作为A公司的职员,最盼望的日子就是每月的8号了,因为这一天是发工资的日子,养家糊口就靠它了。但是对于公司财务处的工作人员来说,这一天则是很忙碌的一天,财务处的小胡最近就在考虑一个问题:如果每个员工的工资额都知道,最少需要准备多少张人民币,才能在给每位职员发工资的时候都不用老师找零呢?这里假设员工的工资都是正整数,单位元,人民币一共有100元、50元、10元、5元、2元和1元六种。

输入

输入数据包含多个测试实例,每个测试实例的第一行是一个整数n(n<=100),表示老师的人数,然后是n个老师的工资(工资<5000)。

输出

每个测试用例输出一行,即凑成钱数值M最少需要的钱币个数。如果凑钱失败,输出“Impossible”。你可以假设,每种待凑钱币的数量是无限多的。

样例输入

3
1 2 3
2
1 2

样例输出

4
2

代码

#可以简单地使用贪心,从100开始除,这里想试试low_bound+回溯的写法
#include <iostream>
 
using namespace std;
 
int n;
int m[6] = {1, 2, 5, 10, 50, 100};
 
int lowbound (int mount) {
    int l = 0, r = 6;
     
    int mid;
    while (l < r) {
        mid = l + r >> 1;
        if (m[mid] > mount) r = mid;
        else l = mid + 1;
    }
     
    return m[l - 1];
}
 
int f (int mount, int cnt) {
    // 查找第一个小于等于的
    if (!mount) return cnt;
     
    int d = lowbound(mount);
         
    return f(mount - d, cnt + 1);
}
 
int main () {
     
    while (cin >> n) {
        int ans = 0;
         
        while (n --) {
            int t;
            cin >> t;
            ans += f(t, 0);
        }   
         
        cout << ans << endl;
    }
     
    return 0;
} 

4 最大连续子序列

题目描述

给定 K 个整数的序列{ N1, N2, …, NK } ,其任意连续子序列可表示为{ Ni, Ni+1,…,Nj} ,其中1 <= i<= j <= K。最大连续子序列是所有连续子序列中元素和最大的一个,例如给定序列{ -2, 11, -4, 13, -5, -2 } ,其最大连续子序列为{ 11, -4, 13 } ,最大和为20。编写程序得到其中最大子序列的和并输出该子序列的第一个和最后一个元素的下标。

输入

测试输入包含若干测试用例,每个测试用例占2 行,第 1 行给出正整数 K( <100000) ,第 2 行给出 K 个整数,每个整数的范围-10000至10000 ,中间用空格分隔。

输出

对每个测试用例, 在 1 行里输出最大和、 最大连续子序列的第一个和最后一个元素的下标,中间用空格分隔。 如果最大连续子序列不唯一, 则输出序号 i 和 j 最小的那个(如输入样例的第 2、3组)。若所有 K 个元素都是负数,则定义其最大和为0,输出"0 0 0"。

样例输入

8
6 -2 11 -4 13 -5 -2 10
20
-10 1 2 3 4 -5 -23 3 7 -21 6 5 -8 3 2 5 0 1 10 3
8
-1 -5 -2 3 -1 0 -2 0
4
-1 -2 -4 -3

样例输出

27 0 7
27 10 19
3 3 3
0 0 0

代码

在这里插入代码片

5 安全路径

题目描述

卫斯理小说经常提及外星人,比如蓝血人。 在土星星球有很多城市,每个城市之间有一条或多条飞行通道, 但是并不是所有的路都是很安全的,每一条路有一个安全系数 s,s 是在 0和1 间的实数 (包括 0 , 1) ,一条从 u 到 v 的通道 P 的安全度为 Safe§ = s(e1)*s(e2)…*s(ek) e1,e2,ek是P 上的边 ,现在蓝血人想出去旅游,面对这这么多的路,他想找一条最安全的路。但是蓝血人的数学不好,想请你帮忙。

输入

输入包括多个测试实例,每个实例包括:
第一行: 一个整数 n。 n 表示城市的个数 n<=1000;
接着是一个 n*n 的矩阵表示两个城市之间的安全系数, (0可以理解为那两个城市之间没有直接的通道 )。
接着是一个整数m (m<=100)表示若干个蓝血人要旅游的路线 ,下面每行有两个数字,表示蓝血人所在的城市和要去的城市。

输出

如果蓝血人无法达到他的目的地,输出 “What a pity!” ,
其他的输出这两个城市之间的最安全道路的安全系数,保留三位小数。

样例输入

3
1 0.5 0.5
0.5 1 0.4
0.5 0.4 1
3
1 2
2 3
1 3

样例输出

0.500
0.400
0.500

代码

#dijstra
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

#define MAX 1010

int n, vis[MAX];
double g[MAX][MAX], d[MAX];

int dijkstra(int x, int y) {
    memset(vis, 0, sizeof vis);
    fill(d, d + MAX, 0);
    d[x] = 1;
    if (x == y) return 1;
    for (int i = 1; i <= n; i ++) {
        int u = -1;
        double maxn = 0; 
        for (int j = 1; j <= n; j ++) {
            if(!vis[j] && d[j] > maxn) {
                u = j;
                maxn = d[j];
            }
        }
        
        if (u == -1) return -1;
        if (u == y) return 1;
        
        vis[u] = 1;
        for (int v = 1; v <= n; v ++)
            if(!vis[v] && g[v][u] && d[v] < d[u] * g[v][u])
                d[v] = d[u] * g[v][u];
     } 
}

int main() {
    while (cin >> n) {
        int i, j, m, x, y;
        for (int i = 1; i <= n; i ++)
            for (int j = 1; j <= n; j ++)
                cin >> g[i][j];
        
		cin >> m;
        
		for (int i = 0; i < m; i ++) {
            cin >> x >> y;
            
            int res = dijkstra(x, y);
            
            if (res == -1)
                cout << "What a pity!" << endl;
            else printf("%.3lf\n", d[y]);
        }           
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值