PAT甲级考试练习

1001

题目:Calculate a+b and output the sum in standard format – that is, the digits must be separated into groups of three by commas (unless there are less than four digits).

大意:提供两个整数,计算两数和,并按照三位一组以逗号分隔输出。

思路:数据范围在 − 1 0 6 < a , b < 1 0 6 -10^6<a,b<10^6 106<a,b<106,可以直接用Int保存两数和;首先理清情况:

  1. sum == 0,直接输入0,推出即可
  2. sum < 0, 提前输出“-”号,将sum取绝对值 s u m ∗ = − 1 sum*=-1 sum=1,进入情况3
  3. sum > 0, 用一个数组存储sum的各位(通过取模获取各位),高位向低位遍历数组输出,每当 i   m o d   3 = 0 , i > 0 i\ mod\ 3 =0, i >0 i mod 3=0,i>0时,则输出“,”;

代码

#include<iostream>
#include<vector>
using namespace std;

int main(){
    int a, b;
    cin >> a >> b;
    int sum = a + b;
    if( sum == 0){
        cout << 0;
        return 0;
    }
    if(sum < 0){
        cout << '-';
        sum *= -1;
    }
    vector<int> nums;
    while(sum != 0){
        nums.emplace_back(sum % 10);
        sum /= 10;
    }
    for(int i = nums.size() - 1; i >= 0 ; i--){
        cout << nums[i];
        if(i % 3 == 0 && i > 0) cout << ',';
    }
    return 0;
}

1002

题目:you are supposed to find A+B where A and B are two polynomials.Each input file contains one test case. Each case occupies 2 lines, and each line contains the information of a polynomial:
K   N 1   a N 1   . . .   N i   a N i K\ N_1\ a_{N1}\ ... \ N_i\ a_{Ni} K N1 aN1 ... Ni aNi
样例

input:
2 1 2.4 0 3.2
2 2 1.5 1 0.5
output:
3 2 1.5 1 2.9 0 3.2

大意:多项式加法
思路:1:双数组分别存储两个多项式的输入情况,poly[i]即表示第 N i N_i Ni的对应 a N i a_{Ni} aNi;同时遍历两个数组,求各位的和,若和不为0,则添加到结果集中。按照输出要求,用printf正则匹配输出。2:优化空间,由于两个数组求和,则可以只使用一个数组,第二个多项式在输入时直接累加到第一个多项式的多项式数组中。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int N = 1010;

float poly[N];

int main(){
    int k;
    cin >> k;
    while( k --){
        int ex;
        float co;
        cin >> ex >> co;
        poly[ex] = co;
    }
    cin >> k;
    while(k --){
        int ex;
        float co;
        cin >> ex >> co;
        poly[ex] += co;
    }
    vector<pair<int,float>> res;
    for(int i = 0 ; i < 1010; i++){
        if(poly[i] != 0){
            pair<int,float> temp = {i, poly[i]};
            res.emplace_back(temp);
        }
    }
    cout << res.size();
    for(int i = res.size() - 1; i >= 0; i--){
        printf(" %d %.1f", res[i].first, res[i].second);
    }
    return 0;
}

1003

题目:As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

大意:给定一个无向图、起点、终点,以及各城市的救援人数,统计从起点到终点的最短路径有几条,最短路径中能够携带的最大救援人数有多少。

思路:一般最短路径问题:1、采用Dijkstra单源最短路算法,2、DFS搜索;本题需要计算最短路数目,采用DFS结合回溯搜索进行统计,当同为最短路时,只需要将救援人数取一个最大值即可(何时抵达终点,即DFS递归中的起点与终点相同时则到达目的地)

代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

void count_shortest_path(int, int, int, int);

const int N = 510;
int n, m, c1, c2;
int grid[N][N], amounts[N];		//amounts[i]表示第i个城市的救援队员总数
bool visited[N];
int paths = 0, min_path = 0x3f3f3f3f, max_amount = -1;

int main(){
    cin >> n >> m >> c1 >> c2;
    for(int i = 0 ; i < n; i++){
        cin >> amounts[i];
    }
    while(m--){
        int a, b, c;
        cin >> a >> b >> c;
        grid[a][b] = grid[b][a] = c;
    }
    visited[c1] = true;
    count_shortest_path(c1, c2, 0, amounts[c1]);
    cout << paths << " " << max_amount;
    return 0;
}

void count_shortest_path(int start, int end, int path, int amount){
    if(start == end && path <= min_path){	//此处其实应该再加一个判断当path > min_path 时直接剪枝不用继续递归,第一版没细想,懒的改了,不建议读者像我一样懒惰
        if(path == min_path){
            paths ++;
            max_amount = max(max_amount, amount);
        }else{
            min_path = path;
            max_amount = amount;
            paths = 1;
        }
        return;
    }

    for(int i = 0; i < n; i ++){
        if(grid[start][i] != 0 && !visited[i]){
            visited[i] = true;
            count_shortest_path(i, end, path + grid[start][i], amount + amounts[i]);
            visited[i] = false;
        }
    }
}

1004

题目:A family hierarchy is usually presented by a pedigree tree. Your job is to count those family members who have no child.
ach input file contains one test case. Each case starts with a line containing 0<N<100, the number of nodes in a tree, and M (<N), the number of non-leaf nodes. Then M lines follow, each in the format:
I D   K   I D [ 1 ]   I D [ 2 ] . . . ID\ K \ ID[1] \ ID[2] ... ID K ID[1] ID[2]...
where ID is a two-digit number representing a given non-leaf node, K is the number of its children, followed by a sequence of two-digit ID’s of its children. For the sake of simplicity, let us fix the root ID to be 01.
The input ends with N being 0. That case must NOT be processed.

大意:给定一个树,输出每层的叶子结点个数

思路:1、采用邻接矩阵存储树结构;2、层次遍历树结构,统计每层的叶子结点个数即可;3、注意输出格式要求,可以先输出res[0],再循环输出cout << " " << res[i];
改进: 第一次写的时候第一时间想到的是层次遍历,层次遍历代码相对复杂一点,其实只需要遍历整个树的结点逐个判断就行了(用vector构造邻接表可以直接调用size()返回孩子结点个数,更易判别),所以更简单点可以用DFS遍历树进行判断。

代码:

层次遍历思路:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;

const int N = 101;

int n, m;
int grid[N][N];
vector<int> res;

void BFS();

int main(){
    cin >> n >> m;
    while (m--){
        int id, k;
        cin >> id >> k;
        int child;
        for(int i = 0; i < k; i++){
            cin >>child;
            grid[id][child] = 1;
        }
    }
    BFS();
    cout << res[0];	//处理输出格式要求
    for(int i = 1 ; i < res.size(); i ++){
        cout <<" "<<res[i];
    }
    return 0;
}
// 层次遍历好久没写了,写题的时候零时想的,不建议看,只需要套常规层次遍历模板,增加一个计数统计就行了。
void BFS(){
    queue<int> q;
    q.push(01);
    while(!q.empty()){
        int size = q.size();
        int cnt = 0;
        for(int i = 0 ; i < size; i ++){
            int item = q.front();
            bool leaf = true;  //判断当前结点是否是叶子结点          
            q.pop();
            for(int j = 1 ; j <= n; j ++){
                if(grid[item][j] == 1){
                    q.push(j);
                    leaf = false;
                }
            }
            if(leaf) cnt ++;
        }
        res.emplace_back(cnt);
    }
}

DFS解法:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int N = 101;

int n, m, max_level;
vector<int> childrens[N];
int res[101] = {0};

void DFS(int, int);

int main()
{
    cin >> n >> m;
    while( m-- )
    {
        int id, k, child;
        cin >> id >> k;
        for(int i = 0 ; i < k; i++){
            cin >> child;
            childrens[id].emplace_back(child);
        }
    }
    DFS(1, 1);
    cout << res[1];
    for(int i = 2; i <= max_level; i++){
        cout << " " << res[i];
    }
    return 0;
}

void DFS(int node, int cur_level){
    max_level = max(max_level, cur_level);
    if(childrens[node].size() > 0){
        for(auto item : childrens[node]){
            DFS(item, cur_level + 1);
        }
    }else{
        res[cur_level] ++;
    }
}

1005

题目:Given a non-negative integer N, your task is to compute the sum of all the digits of N, and output every digit of the sum in English.

大意:提供一个非负整数串,输出整数串各位之和(用英文字母输出和)

思路:1、提取整数串的各位并求和(用long long存储和避免溢出)2、哈希映射输出结果。

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

string NUMBER[10] = {"zero", "one", "two", "three", "four", "five", "six", "seven",
             "eight", "nine"};

int main(){
    
    string N;
    long long sum = 0;
    cin >> N;
    for(auto item : N){
        sum += item - '0';
    }
    vector<string> res;
    while(sum != 0){
        int num = sum % 10;
        sum /= 10;
        res.emplace_back(NUMBER[num]);
    }
    //注意一下输出要求
    if(res.empty()) cout << "zero";
    else{
        cout<< res[res.size()-1];
        for(int i = res.size() - 2; i >= 0 ; i --){
            cout << " " << res[i];
        }        
    }
    return 0;
}

1006

题目大意:给定M个人的数据信息(id,进门时间,出门时间),返回最早进门和最晚出门的ID。

思路:1、按照要求设置变量存储进出门时间值,并分别与假定最早出门时间对比,依次更新最早进出门时间,并记录对于ID。2、如何处理时间比大小问题,题目给定的是时间字符串,可以采用字符串分割,将HH:MM:SS格式转化为以秒为单位,再进行比较(其实可以直接用字符串比较也可以比较HH:MM:SS时间)

代码

 #include<iostream>
 #include<string.h>
 #include<algorithm>
 using namespace std;

int translate_time(string);

int m, first = 24 * 60 * 60, last = 0;
string unlock , lock;

int main()
{
    cin >> m;
    while(m --){
        string id, in_time, out_time;
        cin >> id >> in_time >> out_time;
        int translate_in_time, translate_out_time;
        translate_in_time = translate_time(in_time);
        translate_out_time = translate_time(out_time);
        if(translate_in_time < first) unlock = id, first = translate_in_time;
        if(translate_out_time > last) lock = id, last = translate_out_time; 
    }
    cout << unlock <<" "<< lock;
    return 0;
}

int translate_time(string time){
    string hour, minute, second;
    hour = time.substr(0,2);
    minute = time.substr(3,2);
    second = time.substr(6,2);
    return stoi(hour) * 3600 + stoi(minute) * 60 + stoi(second);
}

1007

题目大意:给定一个长度的序列,找出和最大的连续子序列(和相同则输出i,j最小的,也就是选择第一个最大连续子序列),输出该子序列的和,子序列的第一个元素,子序列的最后一个元素。(若给定序列为全负序列,即当最大和小于0时,则输出0、整个序列的第一个元素和最后一个元素)

思路:1、要求连续子序列的和,则可以采用前缀和简化。2、暴力双指针搜索即可(或者用DP简单优化一下:对于以第k个整数为结尾的最大连续子序列和,即sum[k] - min(sum[0],…,sum[k-1]),那么可以动态存储k点前的最小前缀和值。

代码

#include<iostream>
#include<cstring>
using namespace std;
const int N = 10010;

int k, largest = -1;
int a[N], sum[N];

int main()
{
    cin >> k;
    for(int i = 1; i <= k; i++) cin >> a[i];
    //构造前缀和
    sum[0] = 0;
    for(int i = 1; i <= k; i++) sum[i] = sum[i - 1] + a[i];
    int head = 0;
    int start, end;
    //暴力的话,这里直接改嵌套循环直接计算sum[j] - sum[i], 注意前缀和 sum[3] - sum[1] = a[2] + a[3];
    for(int i = 1; i <=k ; i++){
        if(sum[i] - sum[head] > largest){
            largest = sum[i] - sum[head];
            start = a[head + 1];
            end = a[i];
        }
        if(sum[i] < sum[head]) head = i;
    }
    if(largest < 0) cout << "0 " << a[1] << " " << a[k];
    else{
        cout << largest << " " << start << " " << end;
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值