December 2022 C/C++ (Level 6) real test analysis#中国电子学院#National Youth Software Programming Level Examination

insert image description here

C/C++ Programming (Level 1~8) All real questions・Click here

Question 1: Interval Merging

Given n closed intervals [ai; bi], where i=1,2,…,n. Any two adjacent or intersecting closed intervals can be merged into one closed interval. For example, [1;2] and [2;3] can be combined into [1;3], and [1;3] and [2;4] can be combined into [1;4], but [1;2] and [ 3;4] Merging is not possible.
Our task is to judge whether these intervals can be finally merged into a closed interval, if yes, output the closed interval, otherwise output no.
Time limit: 1000
Memory limit: 65536
input
The first line is an integer n, 3 ≤ n ≤ 50000. Indicates the number of input intervals. After n lines, on the i-th line (1 ≤ i ≤ n), there are two integers ai and bi, separated by a space, indicating the interval [ai; bi] (where 1 ≤ ai ≤ bi ≤ 10000) .
Output
Output one line, if these intervals can be combined into a closed interval, output the left and right boundaries of the closed interval, separated by a single space; otherwise output no.
Sample input
5
5 6
1 5
10 10
6 9
8 10
Sample output
1 10

This problem can be solved by performing a merge operation on closed intervals of the input. We can use a variable to keep track of the current bin range and update this range based on each input closed range.

First, we can sort the input closed intervals according to the left boundary from small to large.

Then, we can use two variables start and end to represent the current range of the merged interval, and the initial values ​​are the left and right boundaries of the first closed interval respectively.

Next, we can traverse the sorted list of closed intervals, and for each closed interval, check whether it intersects or is adjacent to the current merged interval. If they intersect or are adjacent, update the current range of the combined interval, update start to the left boundary of the current closed interval, and update end to the right boundary of the current closed interval.

Finally, if after traversing all closed intervals, the final merged interval range is equal to the minimum and maximum values ​​of the input closed interval list, it means that these intervals can be finally merged into a closed interval, and output the left and right boundaries of this closed interval; otherwise output " no".

Here is an example solution implemented in C language:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    
    
    int left;
    int right;
} Interval;

int compare(const void *a, const void *b) {
    
    
    Interval *intervalA = (Interval *)a;
    Interval *intervalB = (Interval *)b;

    return intervalA->left - intervalB->left;
}

int main() {
    
    
    int n;
    scanf("%d", &n);

    Interval intervals[n];

    int i;
    for (i = 0; i < n; i++) {
    
    
        scanf("%d %d", &(intervals[i].left), &(intervals[i].right));
    }

    qsort(intervals, n, sizeof(Interval), compare);

    int start = intervals[0].left;
    int end = intervals[0].right;

    for (i = 1; i < n; i++) {
    
    
        if (intervals[i].left <= end) {
    
    
            if (intervals[i].right > end) {
    
    
                end = intervals[i].right;
            }
        } else {
    
    
            printf("no\n");
            return 0;
        }
    }

    if (start == intervals[0].left && end == intervals[n - 1].right) {
    
    
        printf("%d %d\n", start, end);
    } else {
    
    
        printf("no\n");
    }

    return 0;
}

The program first defines a structure (Interval) representing a closed interval, including the left boundary and right boundary properties.

In the main function, first read the number n of intervals, and create an array (intervals) for storing all closed intervals.

Then, use a loop to read the left and right bounds of each closed interval from the input and store them in the corresponding array elements.

Next, use the qsort function to sort the closed interval array, and the sorting rules are defined by the compare function. The compare function sorts in descending order of the left boundary.

Then, two variables (start and end) are created and their initial values ​​are set to the left and right boundaries of the first closed interval.

Use a loop to traverse the sorted array of closed intervals, and for each closed interval, determine whether it intersects or is adjacent to the current merged interval. If they intersect or are adjacent, update the current range of the combined interval, update start to the left boundary of the current closed interval, and update end to the right boundary of the current closed interval.

Finally, if after traversing all closed intervals, the left boundary of the final merged interval range is equal to the minimum value of the closed interval array, and the right boundary is equal to the maximum value of the closed interval array, it means that these intervals can be finally merged into one closed interval, output The left and right boundaries of this closed interval; otherwise output "no".

Note: For convenience, this program assumes that the input closed intervals have been sorted from small to large left bounds. If the input closed intervals are not sorted, you can use the qsort function to sort after reading all closed intervals.

In addition, the program uses functions in the C standard library, so the corresponding header files (stdio.h and stdlib.h) need to be included.

Question 2: Phone Number

Given some phone numbers, please judge whether they are consistent, that is, whether a certain phone number is a prefix of another phone number. For example:
Emergency 911
Alice 97 625 999
Bob 91 12 54 26
In this example, it is impossible for us to dial Bob’s phone number, because Emergency’s phone number is its prefix, and when dialing Bob’s phone number, Emergency will be connected first, so these The phone numbers are not consistent.
Time limit: 1000
Memory limit: 65536
input
The first line is an integer t, 1 ≤ t ≤ 40, indicating the number of test data. The first line of each test sample is an integer n, 1 ≤ n ≤ 10000, and each of the next n lines is a phone number with no more than 10 digits.
Output
For each test data, if it is consistent output "YES", if not output "NO".
Sample input
2
3
911
97625999
91125426
5
113
12340
123440
12345
98346
Sample output
NO
YES

This problem can be solved by building a prefix tree (Trie). A prefix tree is a tree-like data structure used to store a set of strings and support efficient lookup of string prefixes.

First, we can define a prefix tree node structure, including a Boolean variable isEnd indicating whether it is the end of a string, and an array of pointers to child nodes.

Then, we can use a function to build the prefix tree. For each phone number, we start at the root node and iterate through each digit of the number in turn. If the child node corresponding to the current number does not exist, we create a new node and update the child node pointer of the current node. Then, point the current node to the child node and continue traversing the next digit. Finally, set the isEnd flag of the current node to true, indicating that the current node is the end of a phone number.

Next, we can use another function to determine whether a set of phone numbers match. For each phone number, we start at the root node and iterate through each digit of the number in turn. If the isEnd flag of the current node is true, it means that the current number is the prefix of another number, and return "NO". If the child node corresponding to the current number does not exist, it means that the current number is not a prefix of any number, and returns "YES". Otherwise, point the current node to the child node and continue traversing the next digit. If "NO" is not returned after traversing all numbers, return "YES".

Here is an example solution implemented in C language:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

#define NUM_CHILDREN 10

typedef struct TrieNode {
    
    
    bool isEnd;
    struct TrieNode* children[NUM_CHILDREN];
} TrieNode;

TrieNode* createNode() {
    
    
    TrieNode* node = (TrieNode*)malloc(sizeof(TrieNode));
    node->isEnd = false;
    memset(node->children, 0, sizeof(node->children));
    return node;
}

void insert(TrieNode* root, char* phoneNumber) {
    
    
    TrieNode* curr = root;
    int len = strlen(phoneNumber);

    for (int i = 0; i < len; i++) {
    
    
        int index = phoneNumber[i] - '0';

        if (curr->children[index] == NULL) {
    
    
            curr->children[index] = createNode();
        }

        curr = curr->children[index];
    }

    curr->isEnd = true;
}

bool isConsistent(TrieNode* root, char* phoneNumber) {
    
    
    TrieNode* curr = root;
    int len = strlen(phoneNumber);

    for (int i = 0; i < len; i++) {
    
    
        int index = phoneNumber[i] - '0';

        if (curr->isEnd) {
    
    
            return false;
        }

        if (curr->children[index] == NULL) {
    
    
            return true;
        }

        curr = curr->children[index];
    }

    return true;
}

void freeTrie(TrieNode* root) {
    
    
    if (root == NULL) {
    
    
        return;
    }

    for (int i = 0; i < NUM_CHILDREN; i++) {
    
    
        freeTrie(root->children[i]);
    }

    free(root);
}

int main() {
    
    
    int t;
    scanf("%d", &t);

    while (t--) {
    
    
        int n;
        scanf("%d", &n);

        TrieNode* root = createNode();

        bool consistent = true;

        while (n--) {
    
    
            char phoneNumber[11];
            scanf("%s", phoneNumber);

            if (consistent) {
    
    
                if (!isConsistent(root, phoneNumber)) {
    
    
                    consistent = false;
                }

                insert(root, phoneNumber);
            }
        }

        if (consistent) {
    
    
            printf("YES\n");
        } else {
    
    
            printf("NO\n");
        }

        freeTrie(root);
    }

    return 0;
}

The program first defines a prefix tree node structure (TrieNode), which includes a Boolean variable isEnd indicating whether it is the end of a string, and an array of pointers to child nodes.

Problem 3: Sorting Poker Cards

Suppose there are 36 poker cards here, namely A1 A9, B1 B9, C1 C9, D1 D9, where A represents squares, B represents clubs, C represents hearts, and D represents spades, then set the following sorting rules :
1. For two cards, X1Y1 and X2Y2, X1 and X2 represent A~D, Y1 and Y2 represent 1~9, if X1 and X2 are different, then sort according to D>C>B>A 2
. If X1 and X2 are the same, then compare the size of Y1 and Y2.
For example, for the following four cards, there are the following ascending sorting results:
D3, C4, A4, C1
ascending sorting results are A4, C1, C4, D3
Someone proposed the following sorting strategy:
first establish 9 queues, use According to the size of the storage points, the cards are stored in their respective queues according to the points, and then they are dequeued in sequence from queue 1 to queue 9.
For example, for the above results, after entering the queue in sequence, the result is as follows:
queue 1: C1; queue 3: D3, queue 4: C4, A4,
after they are dequeued in sequence, the result is C1, D3, C4, A4
and then Create 4 queues for storing suits. Store cards in queues 1 to 4 according to suits A to D, and then dequeue in sequence from queue 1 to queue 4.
For example, for the sequences C1, D3, C4, and A4 just dequeued above, put them into the queue in turn, the result is as follows:
Queue 1: A4; Queue 3: C1, C4; Queue 4: D3
After they are dequeued in turn, the result For A4, C1, C4, D3, sorting ends.
According to the above algorithm, please write a program that uses queues to sort playing cards. It is required to sort according to the above sorting rules and according to the method of suit first and then points.
Time limit: 1000
Memory limit: 65536
input
The input is divided into two lines, the first line is an integer n, indicating that there are n cards in total (1<=n<=100) The second line represents each card in the form of XY, where X is A ~D, Y is 1~9
output output
three parts The first part is the result of entering and leaving the team for the first time, expressed by Queue1:..., a total of 9 lines, the results are separated by spaces, the same as below The second part is the first The result of entering and exiting the queue twice is represented by QueueA:..., a total of 4 lines and the third part is one line, that is,
the sample input of the card sorted result (in ascending order) is 8 D8 A6 C3 B8 C5 A1 B5
D3
sample
output
Queue1:A1
Queue2:
Queue3:C3 D3
Queue4:
Queue5:C5 B5
Queue6:A6 Queue7
:
Queue8:D8 B8 Queue9
:
QueueA:A1 A6 QueueB :B5 B8 QueueC:C3 C5 QueueD:D3 D8 A1 A6 B5 B8 C3 C5 D3 D8 Tips When entering and leaving the queue for the second time, 4 of the 9 queues in the first time can be reused. So in fact, only 9 queues need to be opened up.





The following is a poker sorting program written in C language, implemented using a queue:

#include <stdio.h>
#include <stdlib.h>

#define MAX_CARDS 100
#define MAX_QUEUE_SIZE 9

// 定义扑克牌结构体
typedef struct {
    
    
    char suit; // 花色
    int number; // 点数
} Card;

// 定义队列结构体
typedef struct {
    
    
    Card cards[MAX_CARDS];
    int front;
    int rear;
} Queue;

// 初始化队列
void initQueue(Queue *queue) {
    
    
    queue->front = 0;
    queue->rear = -1;
}

// 判断队列是否为空
int isQueueEmpty(Queue *queue) {
    
    
    return queue->front > queue->rear;
}

// 入队
void enqueue(Queue *queue, Card card) {
    
    
    queue->rear++;
    queue->cards[queue->rear] = card;
}

// 出队
Card dequeue(Queue *queue) {
    
    
    Card card = queue->cards[queue->front];
    queue->front++;
    return card;
}

// 按花色入队
void enqueueBySuit(Queue *queues, char suit, Card card) {
    
    
    int index;
    switch (suit) {
    
    
        case 'A':
            index = 0;
            break;
        case 'B':
            index = 1;
            break;
        case 'C':
            index = 2;
            break;
        case 'D':
            index = 3;
            break;
        default:
            return;
    }
    enqueue(&queues[index], card);
}

// 按花色出队
void dequeueBySuit(Queue *queues, char suit, Queue *resultQueue) {
    
    
    int index;
    switch (suit) {
    
    
        case 'A':
            index = 0;
            break;
        case 'B':
            index = 1;
            break;
        case 'C':
            index = 2;
            break;
        case 'D':
            index = 3;
            break;
        default:
            return;
    }
    while (!isQueueEmpty(&queues[index])) {
    
    
        Card card = dequeue(&queues[index]);
        enqueue(resultQueue, card);
    }
}

// 比较两张牌的大小
int compareCards(Card card1, Card card2) {
    
    
    if (card1.suit != card2.suit) {
    
    
        switch (card1.suit) {
    
    
            case 'D':
                return -1;
            case 'C':
                if (card2.suit == 'D')
                    return 1;
                else
                    return -1;
            case 'B':
                if (card2.suit == 'D' || card2.suit == 'C')
                    return 1;
                else
                    return -1;
            case 'A':
                if (card2.suit == 'D' || card2.suit == 'C' || card2.suit == 'B')
                    return 1;
                else
                    return -1;
        }
    } else {
    
    
        return card1.number - card2.number;
    }
    return 0;
}

// 扑克牌排序
void sortCards(Card *cards, int n) {
    
    
    Queue queues[MAX_QUEUE_SIZE]; // 9个队列
    Queue resultQueue; // 结果队列
    Card sortedCards[MAX_CARDS]; // 排序后的牌
    int i, j;

    // 初始化队列
    for (i = 0; i < MAX_QUEUE_SIZE; i++) {
    
    
        initQueue(&queues[i]);
    }
    initQueue(&resultQueue);

    // 第一次进队出队,按点数入队
    for (i = 0; i < n; i++) {
    
    
        enqueueBySuit(queues, cards[i].suit, cards[i]);
    }

    printf("Queue1:");
    while (!isQueueEmpty(&queues[0])) {
    
    
        Card card = dequeue(&queues[0]);
        printf(" %c%d", card.suit, card.number);
        enqueue(&resultQueue, card);
    }
    printf("\n");

    // 第二次进队出队,按花色入队
    for (i = 0; i < MAX_QUEUE_SIZE; i++) {
    
    
        dequeueBySuit(queues, 'A' + i, &resultQueue);
    }

    printf("QueueA:");
    for (i = 0; i < MAX_QUEUE_SIZE; i++) {
    
    
        while (!isQueueEmpty(&queues[i])) {
    
    
            Card card = dequeue(&queues[i]);
            printf(" %c%d", card.suit, card.number);
            enqueue(&resultQueue, card);
        }
    }
    printf("\n");

    // 排序后的结果
    printf("Result:");
    i = 0;
    while (!isQueueEmpty(&resultQueue)) {
    
    
        sortedCards[i] = dequeue(&resultQueue);
        printf(" %c%d", sortedCards[i].suit, sortedCards[i].number);
        i++;
    }
    printf("\n");
}

int main() {
    
    
    int n;
    scanf("%d", &n);
    Card cards[MAX_CARDS];
    int i;

    // 读取扑克牌
    for (i = 0; i < n; i++) {
    
    
        char suit;
        int number;
        scanf(" %c%d", &suit, &number);
        cards[i].suit = suit;
        cards[i].number = number;
    }

    // 扑克牌排序
    sortCards(cards, n);

    return 0;
}

Using the above code, you can input the number of poker cards and the suit and rank of each card, and then the program will sort according to the given sorting rules, and output the results of entering and exiting the team and the sorted results.

Topic 4: Modern Art

After getting bored with two-dimensional artwork, the great art cow Picowso decided to pursue a more niche art form, one-dimensional painting.
Although her paintings can currently be represented by an array of colors with a length of N(1 100000), her creative style remains the same: from a blank rectangular canvas, draw some rectangles continuously, then In one dimension, these rectangles are just an interval. She uses N colors and the color number is 1 N to create, each color is used only once, and the color used later can completely cover the previous color at the same position.
Much to Picowso's dismay, her competitor, Moonet, seems to have figured out how to replicate these one-dimensional drawings of hers. Moonet would paint disjoint intervals, wait for the colors to dry, and then paint additional intervals until finished painting. Moonet can only draw at most one interval of each color at a time, but he can draw multiple disjoint intervals of different colors at a time, as long as these intervals do not overlap. Moonet then proceeds to the next round of drawing. Please calculate how many rounds Moonet needs to draw in order to copy a painting.
Time limit: 10000
Memory limit: 65536
Input
The first line is an integer N, and the next N lines contain N integers. The range 0 to N represents the color of each grid point on the tape, and 0 means no coloring.
Output
Output one line, the minimum number of rounds needed to copy this painting, if this painting cannot be Picowso's painting output -1 (for example, this painting cannot be created by drawing one layer at a time)
Sample input
7
0
1
4
5
1
3
3
Sample output
2
TIP
In this example, the first round is painted as 0111133 and the second round is painted as 0145133, so two rounds are required.

Here is the C language code to solve this problem:

#include <stdio.h>
#include <stdlib.h>

int main() {
    
    
    int N;
    scanf("%d", &N);
    
    int *colors = (int *)malloc((N+1) * sizeof(int));
    int *visited = (int *)calloc((N+1), sizeof(int));
    
    for (int i = 1; i <= N; i++) {
    
    
        scanf("%d", &colors[i]);
    }
    
    int rounds = 0;
    int maxIndex = 0;
    
    while (maxIndex < N) {
    
    
        int nextMaxIndex = maxIndex;
        
        for (int i = 1; i <= N; i++) {
    
    
            if (!visited[i] && colors[i] == maxIndex + 1) {
    
    
                visited[i] = 1;
                nextMaxIndex = i;
            }
        }
        
        if (nextMaxIndex == maxIndex) {
    
    
            printf("-1\n");
            free(colors);
            free(visited);
            return 0;
        }
        
        maxIndex = nextMaxIndex;
        rounds++;
    }
    
    printf("%d\n", rounds);
    
    free(colors);
    free(visited);
    
    return 0;
}

The program first reads an input integer N, representing the number of colors. It then uses dynamic memory allocation to create two arrays: colors and visited. The colors array is used to store the color of each grid point, and the visited array is used to keep track of the grid points that have been visited.

Next, the program uses a loop to read N lines of input and stores each color in the colors array.

The program then began simulating Moonet's process of duplicating the painting. It uses a loop to find the currently unvisited grid point with the largest color value (maxIndex + 1) and marks it as visited. Then, it updates maxIndex to the index of the grid point and increments the number of rounds.

If no unvisited grid with the largest color value can be found in a certain round, it means that Picowso's painting cannot be copied, and the program outputs -1 and ends.

Finally, the program outputs the number of rounds and frees the dynamically allocated memory.

Guess you like

Origin blog.csdn.net/gozhuyinglong/article/details/132638648