Honorary course of data structure - the seventh experiment - problem solving Report

Posted by bran on Mon, 31 Jan 2022 07:37:16 +0100

1, Sequence scheduling

subject

There is A sequence of N numbers A: 1, 2,..., n. There is A LIFO container d with A capacity of C. If A sequence consisting of 1 to n is given, can it be obtained by A using the insertion and deletion operations of container D.

Input format:

In the first line, there are two integers T and C separated by spaces, which respectively represent the number of groups queried and the capacity of the container, 1 ≤ t ≤ 10, 1 ≤ C ≤ N.

Lines 2 to T+1, the first integer N of each line, represents the number of elements of the sequence, 1 ≤ N ≤ 10000. The next N integers represent the sequence of queries.

Output format:

Line T. If the sequence of group i can be obtained, line i outputs Yes; Otherwise, line i outputs No,1 ≤ i ≤ T.

Input sample:

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

Output example:

No
Yes

Problem solving ideas

Establish a stack to realize this process. First, store the sequence to be obtained in an array, and then use the loop to press the sequence of 1, 2,..., n into the stack. Press an element in each cycle. At the same time, after pressing the element in this cycle, compare the element at the top of the stack with the sequence to be obtained. If it is the same, get out of the stack, Otherwise, continue the next cycle until N cycles are carried out. If the stack is empty, you can get the output "Yes", otherwise you can't get the output "No".

Reference code

#include<bits/stdc++.h>

using namespace std;

const int maxn = 10001;

stack<int> s;

int a[maxn];

int main(){
	//while(!s.empty())  s.pop();
	int T,C;
	int flag;
	scanf("%d%d",&T, &C);
	while(T){
		int N;
		scanf("%d",&N);
		for(int i = 1; i <= N; i++){
			scanf("%d",&a[i]);
		}
		int j = 1; 
		for(int i = 1; i <= N; i++){
			if(s.size() < C ) s.push(i);
			else break;
			while(1){
				if(s.top() == a[j]) {
					s.pop();
					j++;
				}
				if(s.empty() || s.top() != a[j]) break;
			}
		}
		if(s.empty()) printf("Yes\n");
		else printf("No\n");
        T--;
	}
	return 0;
}

2, Maximum and minimum deviation

subject

For n positive integers, perform the following operations: delete two numbers a and b each time, and then add a new number: a*b+1. Go on until there is only one number left. Among all the numbers finally obtained by this operation mode, the maximum is max and the minimum is min. calculate max min.

Input format:

Line 1: n, the number of elements in the sequence, 1 < = n < = 16.

Line 2: n numbers separated by spaces x, x < = 10.

Output format:

1 line, Max min.

Input sample:

3
2 4 3

Output example:

2

Problem solving ideas

In fact, there is a rule in this problem, that is, if max is required, extract two smallest ones from integers for calculation each time; Similarly, if min is required, extract the two largest ones from the integer each time and calculate them only.
Because it is either the minimum or the maximum every time, I use the priority queue to achieve the maximum and minimum operation.

Reference code

#include<bits/stdc++.h> 

using namespace std;

int min;

priority_queue<int,vector<int>, less<int> > pq1;// Sort objects using the incremental less < int > function
priority_queue<int,vector<int>, greater<int> > pq2;



int main(){
	int n;
	scanf("%d",&n);
	int a;
	while(!pq1.empty()) pq1.pop();
	while(!pq2.empty()) pq2.pop();
	for(int i = 1; i <= n; i++){
		scanf("%d", &a);
		pq1.push(a);
		pq2.push(a);
	}
	int min, max;

	for(int i = 1; i <= n-1; i++){
		a = pq1.top(); pq1.pop();
		min = a*pq1.top() + 1; pq1.pop();
		pq1.push(min);
		
		a = pq2.top(); pq2.pop();
		max = a*pq2.top() + 1; pq2.pop();
		pq2.push(max);
	}
	printf("%d",max-min);
	return 0;
}

3, Shortest path length of binary tree

subject

Given a binary tree T, each node is assigned a weight. Calculate the shortest path length from the root node to all nodes. Path length is defined as the sum of the weights of each vertex on the path.

Input format:

The first line, an integer n, represents the number of nodes of binary tree T, node number 1... N, 1 ≤ n ≤ 20000.

The second line, n integers separated by spaces, represents the first root sequence of T, and the nodes in the sequence are represented by numbers.

The third line, n integers separated by spaces, represents the middle root sequence of T, and the nodes in the sequence are represented by numbers.

Line 4, n integers Wi, separated by spaces, represents the weight of nodes in T, - 10000 ≤ Wi ≤ 10000, 1 ≤ i ≤ n.

Output format:

1 line, n integers, indicating the shortest path length from the root node to all other nodes.

Input sample:

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

Output example:

1 0 3 3

Problem solving ideas

Because it is a binary tree, there is only one path from each two root nodes to other nodes, that is, finding the shortest length is very simple. The difficulty lies in building the tree. The topic gives the first root and middle root, that is, you can first determine the root according to the first root order, and then find the root node in the middle root order. Divide the middle root order into left and right subtrees, and solve it recursively again to complete the tree building.

Reference code

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

const int maxn = 20001;

int wei[maxn];
int len[maxn];

int pre[maxn];//First root 
int in[maxn];//Middle root 
typedef struct BiNode
{
    int date;
    BiNode* LChild;
    BiNode* RChild;
}*BiTree;
void  CreateBiTree(BiTree &root,int preLeft, int preRight, int inLeft, int inRight)
{
	if (preLeft > preRight)  root=NULL;
	else
	{
		root = new BiNode;
		int mid = -1;
		for (int i = inLeft; i <= inRight; i++)
		{
			if (in[i] == pre[preLeft])
			{
				mid = i;
				break;
			}
		}
		root->date = in[mid];
		CreateBiTree(root->LChild,preLeft + 1, preLeft + mid - inLeft, inLeft, mid - 1);
		CreateBiTree(root->RChild,preRight + mid - inRight + 1, preRight, mid + 1, inRight);
	}
}
void solute(BiTree root){
	if(root->LChild!=NULL)	{ len[root->LChild->date] = len[root->date] + wei[root->LChild->date]; solute(root->LChild);  } 
	if(root->RChild!=NULL)  { len[root->RChild->date] = len[root->date] + wei[root->RChild->date]; solute(root->RChild);  } 
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i = 0; i < n; i++){
		scanf("%d",&pre[i]);
	}
	for(int i = 0; i < n; i++){
		scanf("%d",&in[i]);
	}
	for(int i = 1; i <= n; i++){
		scanf("%d",&wei[i]);
	}
	int preLeft=0;int preRight=0;int inLeft=0;int inRight;
	preRight = inRight = n - 1;
	BiTree root=new BiNode;
	CreateBiTree(root,preLeft,preRight,inLeft,inRight);
	
	len[root->date] = wei[root->date];
	
	solute(root);
	
	for(int i = 1; i <= n; i++) {
		printf("%d",len[i]);
		if(i!=n) printf(" ");
	}
	return 0;
}

4, Scheme count

subject

Assembling a product requires n parts. It takes time to produce each part. The production of parts can be carried out in parallel. The production of some parts has a sequential relationship. Only after all the previous parts of a part have been produced can the production of this part be started. How to reasonably arrange the process in order to complete the production of all parts in the least time. How many kinds of key schemes are there when the minimum time is guaranteed? The key scheme refers to a part production sequence from the production start time to the end time. The relationship between two adjacent parts in the sequence belongs to the set of sequential relationships between parts given in advance, and the production of each part in the sequence cannot be postponed.

Input format:

In the first line, there are two integers n and m, separated by spaces, representing the number of parts and the number of relationships respectively. The part number is 1... N, 1 ≤ n ≤ 10000, 0 ≤ m ≤ 100000.

The second line, n integers Ti, separated by spaces, represents the production time of part i, 1 ≤ i ≤ n, 1 ≤ Ti ≤ 100.

Lines 3 to m+2, two integers i and j in each line, separated by spaces, indicate that part I is to be produced before part J.

Output format:

Line 1, an integer, the minimum time to complete production.

Line 2, 1 integer, number of key schemes, up to 100 bits.

If the production cannot be completed, only 1 line is output, including 1 integer 0

Input sample:

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

Output example:

4
2

Problem solving ideas

First of all, we can see that this is a problem of finding the critical path, but because the algorithm of the critical path is for the AOE network, but this problem gives the AOV network, so we need to convert the AOV network into the AOE network; There are two conversion methods mentioned in the class: 1) introduce the mirror point v 'for each point v, and put the point weight on the new edge < V, V' >; The original edge < u, V > is converted to < u ', V >. 2) Introduce a virtual source point and a virtual sink point. (I use the latter).
Another problem is that the number of schemes may be as high as 100, so high-precision calculation is required;
Next is the concrete implementation of the code

Reference code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector> 
#include<stack>

using namespace std;

const int maxn = 100001;

vector<pair<int, int> > vec[maxn];  //It is used to store the weights of nodes and paths that are later produced than this point 
int n, m;
int cost[maxn]; //Time spent in part production 
int count1[maxn];//Penetration of each vertex
int tor[maxn];
int ve[maxn],vl[maxn];//ve [] is the earliest occurrence time and vl [] is the latest occurrence time
int len = 1;//Number of schemes
int ans[101];//Number of schemes 

void TopoOrder(){// Topological sorting algorithm: AOV network 
    stack<int> S;
    S.push(0);
    int k = 0;
	for(int i = 0; i <= n + 1; i++){
		if(S.empty()) {printf("0"); exit(0);} 
		
		int j=S.top(); S.pop();
		tor[k++] = j;
		vector<pair<int, int> >::iterator it; 
		
		for(it = vec[j].begin(); it != vec[j].end(); it++){
			count1[it->first] --;
			if(count1[it->first] == 0) S.push(it->first);
		}
	}
}

void CriticalPath(){//Critical path: AOE network 
    TopoOrder();
	//Calculate the earliest occurrence time of the event
	for(int i = 0; i <= n; i++) ve[i]=0;
	vector<pair<int, int> >::iterator it;
	for(int i = 1; i <= n; i++){
	    for(it = vec[tor[i]].begin(); it != vec[tor[i]].end(); it++){
	    	if(ve[tor[i]] + it->second > ve[it->first])
	    	    ve[it->first] = ve[tor[i]] + it->second;
		}
    }
	//Calculate the latest occurrence time of the event 
	for(int i = 0; i <= n + 1; i++) vl[i]=ve[n + 1];  
	
	for(int i = n; i >= 0; i--){
		for(it = vec[tor[i]].begin(); it != vec[tor[i]].end(); it++){
			if(vl[it->first] - it->second < vl[tor[i]])
			    vl[tor[i]] = vl[it->first] - it->second;
		}
	}
}
void address(){
	int u, v;
	for(int i = 0; i < m; i++){
		scanf("%d%d",&u, &v);
		vec[u].push_back(make_pair(v,cost[u]));
		count1[v]++;
	}
	//Add virtual source point and virtual sink point
	for(int i = 1; i <= n; i++)
	{
		if(count1[i] == 0){
			vec[0].push_back(make_pair(i,0));
			count1[i]++;
		} 
	}
	for(int i = 1; i <= n; i++){
		if(vec[i].size() == 0){
			vec[i].push_back(make_pair(n+1,cost[i]));
			count1[n+1]++;
		}
	}
}
void mul(int num){
	int x = 0,temp;// x is carry; temp is the result of the current bit multiplied by it 
	int j = 1;
	while(j <= len){
		temp = ans[j-1]*num + x;
		ans[j-1] = temp%10;
		x = temp/10;
		j++;
	}
	while(x){
			ans[len] = x % 10;
			len++;
			x = x / 10;
		}
}
void Cou(){
	for(int i = 0; i <= n; i++){
		int sum = 0;
        vector<pair<int,int> >::iterator it; 
        for(it = vec[i].begin(); it != vec[i].end(); it++){
            //k=(*it).first;
            int vee = ve[i];
            int vll = vl[it->first]-it->second;
            if(vll == vee){
                sum++;
            }
		}
		if(sum != 0) mul(sum);
	}
}
int main(){
	ans[0] = 1;
	scanf("%d%d",&n, &m);
	for(int i = 1; i <= n; i++){
		scanf("%d",&cost[i]);
	}
	address();
	
	CriticalPath();
	
	Cou(); 
	
	printf("%d\n",vl[n + 1]);
	for(int i = len-1; i >= 0; i--) printf("%d",ans[i]);
	return 0;
}