Questions and solutions of 2021 algorithm design and analysis practice examination of China University of mining and Technology (Xin'an Edition)

Posted by cwncool on Thu, 23 Dec 2021 13:05:43 +0100

Say before:

Due to this exam, I don't know which brother of Xin'an hacked the school's OJ platform, resulting in more than 100 people unable to log in to OJ at the same time, and the exam was forced to be terminated for half an hour However, because a few students just logged in for a short meeting and saw the questions (such as me), the school changed a new set of questions for the sake of fairness
Next, I will liberate the two sets of questions and the corresponding questions below for your study and reference!

Volume A:

1. Caesar encryption

Title Description:
Caesar encryption, or Caesar encryption, Caesar transform, transform encryption, is the simplest and most well-known encryption technology. It is a replacement encryption technology. All letters in plaintext are shifted backward (or forward) according to a fixed number on the alphabet and replaced with ciphertext.

For example, when the offset is shifted 3 to the left:

Plaintext alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Ciphertext alphabet: DEFGHIJKLMNOPQRSTUVWXYZABC
When in use, the encryptor finds the position of each letter in the message to be encrypted in the plaintext alphabet and writes down the corresponding letter in the ciphertext alphabet. The person who needs to decrypt operates in reverse according to the previously known key to obtain the original plaintext. For example:

Plaintext: THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
 Ciphertext: WKH TXLFN EURZQ IRA MXPSV RYHU WKH ODCB GRJ
 Now give you a string S(The length will not exceed 1000000) and an integer k(-1000000000<=k<=1000000000),Represent the ciphertext received by the recipient and the backward offset when encrypting the ciphertext. Your task is to calculate the original plaintext
 Note: only letters will be offset during encryption, and other characters will remain unchanged.

Input:
The input contains multiple groups of data, in which the number of data groups in the first row is t (T < = 10)
The first line of each group of data is a string S, which is composed of numbers, letters and common characters (excluding spaces), and the second line is an integer k, which represents the backward offset during encryption (| S | < = 10000000, - 1000000000 < = k < = 1000000000)

Output:
For each group of data, a line of string is output to represent the plaintext corresponding to the ciphertext in the input.

Sample input:

1
DEFGHIJKLMNOPQRSTUVWXYZABC
3

Sample output:

ABCDEFGHIJKLMNOPQRSTUVWXYZ

Solution:
Water problem, simply change the position of the characters

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        string str;
        cin>>str;
        int k;
        cin>>k;
        int n = str.size();
        for(int i=0; i<n; i++)
        {
            str[i] = 'A' + (str[i]-'A'-k+26)%26;
        }
        cout<<str<<endl;
    }
    return 0;
}

2. Jumping game II

Title Description:
Given an array of nonnegative integers, assume that your initial position is the first subscript of the array. Each element in the array represents the maximum length you can jump at that position. Your goal is to reach the last subscript and use the least number of jumps. For example: A = [2,3,1,1,4], the minimum number of jumps to the last subscript is 2. (jump 11 steps from subscript 0 to 1, then jump 3 steps to reach the last subscript. Two times in total)

Input:
In the first line, enter A positive integer n(1 ≤ n ≤ 100), and in the next line, enter n integers to represent array A.

Output:
Finally, the minimum number of jumps is output.

Sample input:

5
3 1 1 1 1

Sample output:

2

Solution:
This question is the same as the one I did on the force button before. It's relatively simple If a grid as a take-off point can jump for a distance of 3, it means that the next three grids can be used as a take-off point You can try to jump once for each grid that can be used as the take-off point, and constantly update the farthest distance you can jump.
If taking off from this take-off point is called the first jump, then taking off from the back three squares can be called the second jump.
Therefore, at the end of a jump, starting from the next grid and jumping to the farthest distance now are the take-off points of the next jump.
Each jump is simulated with a for loop. After one jump, update the range of the next take-off point. In the new range, the update can jump to the farthest distance Record the number of jumps. If you jump to the end, you get the result.

#include<bits/stdc++.h>
using namespace std;
int Jump(vector<int> &nums)
{
    int n = nums.size(); 
    int start = 0;  //Take off point of each round
    int end = 0;  //The farthest you can reach with each jump
    int Max_pos = 0;   
    int ans = 0;  //Record the number of jumps
    while(Max_pos < n-1)
    {
        for(int i=start; i<=end; i++)  //Constantly update the longest distance you can jump
        {
            Max_pos = max(Max_pos, i+nums[i]);
        }
        start = end+1;  //After the last round of jump reaches the end point, it is re assigned to the take-off point
        end = Max_pos;  //Update the farthest distance you can reach for this jump
        ans++;
    }
    return ans;
}
int main()
{
    int n;
    cin>>n;
    vector<int> nums(n);
    for(int i=0; i<n; i++) cin>>nums[i];
    cout<<Jump(nums)<<endl;
    return 0;
}

3.LongestMatch

Title Description:
A newly established detective firm is using limited intelligence collection and secret intelligence transmission technology between detectives. As they are new to the industry, they know that their information is easy to be captured and modified by other groups. They want to guess the intentions of other groups by checking the changed part of the message. First, they must get the longest matching length. You have to help them.

Input:
The input file may contain multiple test cases. Each case will contain two consecutive serial characters. Blank lines and non alphabetic print punctuation characters may appear. Each line of string will not exceed 1000 characters. The length of each word cannot exceed 20 characters.

Output:
For each input, you must output a line that starts with a non right aligned case with a field width of 2, followed by the longest match, as shown in the sample output. If there is at least one blank line per input, output 'blank!'. Treat non alphabetic punctuation characters as white space.

Sample input:

This is a test.
test
Hello!

The document provides late-breaking information
late breaking.

Sample output:

1. Length of longest match: 1
2. Blank!
3. Length of longest match: 2

Solution:
My initial idea is very simple, that is, first split the two strings and store them in two containers, and then for one container, take out one element in turn to find out whether it exists in the other container Finally get the answer

#include<bits/stdc++.h>
using namespace std;
vector<string> split(string str)  //Separates a string from spaces, and non characters are counted as spaces
{
    vector<string> vec;
    int len = str.length();
    bool flag = true; //Indicates whether a new word begins or not
    int start = 0; //Subscript at the beginning of each word
    for(int i=0; i<len; ++i)
    {
        if(flag && isalpha(str[i]))
        {
            flag = false;
            start = i;
        }
        else if(!isalpha(str[i]))
        {
            flag = true;
            vec.push_back(str.substr(start, i-start));
        }
    }
    if(flag == false) vec.push_back(str.substr(start, len-start)); //If the last one is a letter
    return vec;
}
int LongestMatch(vector<string> vec1, vector<string> vec2)
{
    int ans = 0;
    int size = vec2.size();
    for(int i=0; i<size; i++)
    {
        if(find(vec1.begin(), vec1.end(), vec2[i]) != vec1.end()) ans++;
    }
    return ans;
}
int main()
{
    string str1, str2;
    int i=1;
    while(getline(cin, str1) && getline(cin, str2))
    {
        if(str1.empty() || str2=="")
        {
            printf("%2d.", i++);
            cout<<"Blank!"<<endl;
            continue;
        }
        vector<string> vec1, vec2;
        vec1 = split(str1);
        vec2 = split(str2);
        printf("%2.d", i++);
        cout<<"Length of longest match: "<<LongestMatch(vec1, vec2)<<endl;
    }
    return 0;
}

4.Schedule

Title Description:
There are N schedules, and the ith schedule has a start time si and an end time EI (1 < = i < = N). Every two overlapping schedules cannot be executed on the same machine. For each machine, the working time is defined as the difference between timeend and timestart, where time_{end} is the time to turn off the machine and timestart is the time to turn on the machine. We assume that the machine cannot be shut down between the beginning of time and the end of time. Print the minimum number of machines K to execute all plans. When only K machines are used, print the minimum sum of all working hours.

Input:
The first line contains an integer t (1 < = T < = 100), indicating the number of test cases. Each case contains an integer n (0 < n < = 100000). The next N lines contain two integers si and EI (0 < = si < EI < = 1e9).

Output:
For each test case, print the minimum possible number of machines and the minimum sum of all working hours

Sample input:

1
3
1 3
4 6
2 5

Sample output:

2 8

Solution:
Greedy algorithm, idea:
We should know that this problem requires not only the number of machines required, but also the total time The total time consists of the time of each task plus the waiting time of the machine
Let's do a special sort first. First, split the start Time and end Time of each task. If there are n tasks in total, we will get 2*n nodes Each node has two information, one is Time, and the other is flag (used to indicate whether the node is start Time or end Time) Then sort from small to large. We should also note that if there are two nodes with the same Time, the one with the end Time is placed first Obviously, because

Each time a new task is added, the one with the latest end time in the existing machine (implemented with a stack) is selected, so that we can get the shortest waiting time

// Schedule
// Greedy Algorithm 
// There are N schedules. They have their own start time and end time,
// At the same time, there are many machines. The time on the schedule is the time when the machine is used. However,
// One machine cannot be used at repeated times, so multiple machines may be required to complete the tasks of the schedule,
// The problem requires the sum of the minimum number of machines that meet the requirements and the corresponding time (the waiting time of the machine is also counted).
#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int T;     
    int flag;      //1 indicates that the node is the start time and 2 indicates the end time
}nodes[3000];
bool cmp(Node &a, Node &b)
{
    if(a.T != b.T) return a.T<b.T;
    else return a.flag > b.flag; //If the two times are the same, the one with the end time is put in front Obviously, there must be a corresponding start time before this The task has been completed
}
int main()
{
    int x;
    scanf("%d", &x);
    while(x--)
    {
        int count;
        int pos = 0;  //Represents the position of the node array
        int machine = 0;
        int ans_mach = 0;
        long long ans_sum = 0;
        stack<int> endtime;     //The end time is stored in the stack
        scanf("%d", &count);
        while(!endtime.empty()) endtime.pop();  //Ensure endtime array is empty
        for(int i=0; i<count; i++)
        {
            scanf("%d", &nodes[pos].T);
            scanf("%d", &nodes[pos+1].T);
            nodes[pos].flag = 1;
            nodes[pos+1].flag = 2;
            ans_sum = ans_sum + (nodes[pos+1].T - nodes[pos].T);  //First add up the time of all work tasks
            pos += 2;
        }
        sort(nodes, nodes+pos, cmp);        //Sort from small to large
        for(int i=0; i<pos; i++)
        {
            if(nodes[i].flag == 1)
            {
                machine++;
                if(!endtime.empty())
                {
                    int t = endtime.top();
                    endtime.pop();
                    ans_sum += (nodes[i].T - t);  //We don't care about the start time corresponding to the end time at the top of the stack, because we only need to know the end time to calculate the waiting time And after sorting according to the size, it can be guaranteed that the newly added start time can work on any existing machine! (because all end times are less than the start time, this is also a reason why we don't need to care about the corresponding (start end)
                }
            }
            else
            {
                machine--;
                endtime.push(nodes[i].T);
            }
            ans_mach = max(ans_mach, machine);  //Update maximum machines
        }
        printf("%d %lld\n", ans_mach, ans_sum);
    }
    return 0;
}    

5.Wavio Sequence

Title Description:
The main idea of the topic is to give an array and find out the maximum Wavio Sequence length in the array
What is a Wavio Sequence? It's very simple. Just look at the following two examples!
Wavio is a sequence of integers with the following characteristics:

  1. The length of the Wavio sequence is odd, i.e. L = 2 * n + 1
  2. The first n+1 integers of the waveo sequence are incremental sequences
  3. The n+1 integers after the waveo sequence are decreasing sequences

Example 1 2 3 4 5 4 3 2 1 10
The longest Wavio sequence is 1 2 3 4 5 4 3 2 1, so the answer is 9

Input:
The input file contains less than 75 test cases. Each test case is described as follows:
Each set starts with a positive integer N (1 < = N < = 10000). There are N integers in the next few lines.

Output:
For each set of inputs, print the length of the longest wavio sequence in one line.

Sample input:

10
1 2 3 4 5 4 3 2 1 10
19
1 2 3 2 1 2 3 4 3 2 1 5 4 1 2 3 2 2 1
5
1 2 3 4 5

Sample output:

9
9
1

Solution:
1. Simple violence
Looking at this question, isn't it to find the longest ascending subsequence? Just do it one time straight and one time backwards
Then look at which position the sum of the two is the largest, and that's the answer
Time complexity: 0(n^2)

The code is as follows:

#include<bits/stdc++.h>
using namespace std;
const int inf = 10000;
// Naive algorithm, 0(n^2)
vector<int> Compute(vector<int> &nums)
{
    int n = nums.size();
    vector<int> dp(n, 1);
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<i; j++)
        {
            if(nums[i]>nums[j])
            {
                dp[i] = max(dp[j]+1, dp[i]);
            }
        }
    }
    for(int &x:dp)    //In the range based for loop, the value in the array element can be modified by reference. Direct modification is only to modify the copy, and the original array data remains unchanged.
    {
        if(x == 1)  x = -inf;
    }
    return dp;
}
int main()
{
    int n;
    while(cin>>n && n)
    {
        vector<int> nums(n);
        for(int i=0; i<n; i++) cin>>nums[i];
        vector<int> vec1 = Compute(nums);
        reverse(nums.begin(), nums.end());
        vector<int> vec2 = Compute(nums);
        int max_ans = 1;
        for(int i=0; i<n; i++)
        {
            max_ans = max(max_ans, vec1[i]+vec2[n-i-1]-1);
        }
        cout<<max_ans<<endl;
    }
    return 0;
}

But if possible, the time will be lost TLE

2. Greedy algorithm + binary search
So I think of another optimization method to calculate the length of the longest ascending subsequence through binary search and greedy algorithm
This is the same as the longest increasing subsequence in question 300 of Likou master station We mainly focus on the second method of problem solving, The portal is here , it's easy to understand this topic after reading it!
Time complexity: O(nlogn)

The code is as follows:

// Greedy algorithm + binary search to find the length O(nlogn) of the longest ascending subsequence 
// Considering a simple greed, if we want to make the ascending subsequence as long as possible, we need to make the sequence rise as slowly as possible, so we want the number added at the end of the ascending subsequence to be as small as possible.
// Maintain a one-dimensional array B, which is dynamically expanded. The initial size is 1. B [i] indicates that the length of the longest rising subsequence is the smallest number at the end of all substrings of I,
// We iterate through each element in the array num in turn and update the values of arrays B and Len. If num [J] > b [len], update len = len + 1
// Otherwise, find the pos value of B [I-1] < num [J] < B [i] in B[1...len], and then update B [i] = num [J]
#include<bits/stdc++.h>
using namespace std;
const int inf = 10000;
int lengthOfLIS(vector<int> &nums, int end)    //Get the maximum ascending subsequence length of array num [1.. end]
{
    int n = nums.size();
    if(n == 0) return 0;
    vector<int> B(n+1, 0);
    B[1] = nums[0];
    int len = 1;  //Record the length of the longest ascending subsequence
    for(int i=1; i<end; ++i)
    {
        if(nums[i] > B[len]) B[++len] = nums[i];
        else
        {
            int l = 1, r = len, pos = 0;
            while(l <= r)
            {
                int mid = (l+r) >> 1;
                if(B[mid] < nums[i])
                {
                    pos = mid;
                    l = mid+1;
                }
                else r = mid-1;
            }
            B[pos+1] = nums[i];
        }
    }
    return len;
}
int Ans(vector<int> &nums)
{
    int n = nums.size();
    vector<int> LIS_length;
    vector<int> LIS_length_Reverse;
    for(int i=1; i<=n; i++)
        LIS_length.push_back(lengthOfLIS(nums, i));  //i is end, so i < = n
     reverse(nums.begin(), nums.end());  //Invert array
    for(int i=1; i<=n; i++)
        LIS_length_Reverse.push_back(lengthOfLIS(nums, i));
    for(int i=0; i<n; ++i)
    {
        if(LIS_length[i]==1) LIS_length[i] = -inf;
        if(LIS_length_Reverse[i]==1) LIS_length_Reverse[i] = -inf;
    }
    int max_ans = 1;
    for(int i=0; i<n; ++i)
        max_ans = max(max_ans, LIS_length[i]+LIS_length_Reverse[n-i-1]-1);
    return max_ans;
}
int main()
{
     int n;
    while(cin>>n && n)
    {
        vector<int> nums(n);
        for(int i=0; i<n; i++) cin>>nums[i];
        cout<<Ans(nums)<<endl;
    }
    return 0;
}

The above are all five questions. In fact, to tell the truth, I think it's a little difficult Fortunately, a big brother hacked the OJ platform 😀, So I changed a set of simple questions
If you think this article is helpful to you, welcome to my personal blog--- George's programming cabin Stroll around

Topics: Algorithm