[Screw and nut problem] [Algorithm analysis and design] Suppose we have n screws with different diameters and n corresponding nuts...

Textbook original title

Suppose we have n screws with different diameters and n corresponding nuts. We can only compare a pair of screws and nuts at a time to determine whether the nut is larger than the screw, smaller than the screw, or just fit the screw. However, we can not take two nuts compared , also can not get two screws to compare .

Our problem is to find every pair of matching screws and nuts. To design an algorithm for this problem, its average efficiency must belong to Θ(n log n).

Question Analysis

Maybe after reading the topic, I don't know what it wants us to do, and there is no requirement for input or output. This is very different from what we did with oj, as long as the correct answer is given within the prescribed time and space. And this kind of algorithm analysis design problem, input, output, algorithm and code are all designed by us.

Some students may directly perform quick sorting on the two arrays of screws and nuts, and then output the results. Obviously, fast sorting separately violates the requirements of the above questions.

Before formally designing an algorithm and writing code, we simply think about input and output. The input must be two arrays of nuts and screws. The output can be simpler and output two sorted arrays directly, but the algorithm in the middle meets the requirements of our question.

still have a question! When dividing, the subscripts of the elements are constantly changing, and we did not number the screws and nuts at the beginning. We input and output like this, how do we reflect the "find" marked in the bold above? The output is two ordered arrays, one-to-one correspondence can show that we "find" and "matched". Just like in reality, we can put the matching screws and nuts together directly by manually moving the position without identifying the number.

Said so much, because: before actually writing the code, a certain logical analysis is necessary.

Analysis of Algorithms

 Suppose we randomly choose a screw A at the beginning, and suppose we take the leftmost one in the interval (the initial interval is [0, n-1]). Then find the nut a corresponding to screw A in the corresponding interval of the nut ([0, n-1]). Then change the position of nut a and the leftmost nut of the interval. Then according to the screw A, in the interval, divide the nut a. Note that this is based on screw A, not based on the changed position of nut a! ! ! Otherwise, it would violate the meaning of the question. After the nut is divided once. In the same way, the screw is divided by nut a. Note that the interval at this time is still [0, n-1].

The above is a division algorithm. We need to divide multiple times, and each time we divide it, we must narrow the interval. See the code for details.

Template code for fast queue

First post the template code for quick sorting. This implementation is a bit simpler than the textbook, although the algorithm idea is the same.

void quicksort(int x[],int left,int right)  //快速排序 
{
    if(left<right)
    {
        int i=left,j=right,key=x[left];
        while(i<j)
        {
            while(i<j&&x[j]>=key)
                j--;
            if(i<j)
                x[i++]=x[j];

            while(i<j&&x[i]<=key)
                i++;
            if(i<j)
                x[j--]=x[i];
        }
        x[i]=key;
        
        quicksort(x,left,i-1);
        quicksort(x,i+1,right);
    }
}

Problem-solving code

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

const int N = 9;

void print(int ld[], int lm[]) {
	printf("ld:");
	for (int i = 0; i < N; i++) {
		printf("%d ", ld[i]);
	}
	printf("\n");
	printf("lm:");
	for (int i = 0; i < N; i++) {
		printf("%d ", lm[i]);
	}
	printf("\n");
}

// 进行一次划分 
// [l, r] { 5, 2, 4, 3, 1 }
int partition(int x[], int l, int r, int key) {
	
	// 假设key是螺钉,则首先在螺母中找到与之匹配的螺母
	// 然后与最左侧的螺母交换,使之称为中轴,方便之后作partition 
	for(int i=l; i<=r; i++)
		if(x[i]==key)
		{
			swap(x[i], x[l]);
			break;
		}
	
	// 以key划分螺母 
	int i=l,j=r;
	int t=x[l]; // 暂存中轴 
    while(i<j)
    {
        while(i<j&&x[j]>=key) // 注意,这里要与key做比较,不要用t来比较 
            j--;
        if(i<j)
            x[i++]=x[j];

        while(i<j&&x[i]<=key)
            i++;
        if(i<j)
            x[j--]=x[i];
    }
    x[i]=t;
    
//    printf("i=%d\n", i);
//    for(int i = l; i <= r; i++ ) {
//    	printf("%d ", x[i]);
//	}
	return i;
} 

// [l, r]
void match(int ld[], int lm[], int l, int r) {
	
	if (l < r) {
		// 随便选一个 ld,此处以区间的最左侧(第1个)那个 ld 为例子 
		int ldKey = ld[l];
		// 返回划分之后 lm 的位置 
		// 此时与选的ld对应的lm,(划分之后)在下标为 pos 的位置
		int pos1 = partition(lm, l, r, ldKey);
		
		// 选这个 lm,来划分 ld 
		int lmKey = lm[pos1]; 
        int pos2 = partition(ld, l, r, lmKey); 
        
        // 在这里pos1与pos2相等的 
        print(ld, lm);
        printf("pos1=%d pos2=%d\n", pos1, pos2);
       
		match(ld, lm, l, pos1-1); 
		match(ld, lm, pos1+1, r); 
	}
}


int main() {
    // 为了方便模拟,螺钉和螺母都以数字1-9编号
    // 而且,约定编号越大,直径越大
	int ld[N] = { 5, 9, 3, 7, 1, 8, 2, 4, 6 };
	int lm[N] = { 7, 1, 4, 2, 5, 6, 9, 8, 3 };
		
	match(ld, lm, 0, N-1);
	
	return 0;
}

"Attention, here to be compared with the key, do not use t to compare."

Some people may not understand the comment. Because screws and nuts are represented by the same number, the difference may not be felt.

Suppose you use lowercase letters to represent screws and uppercase letters to represent nuts. Then the comparison in the above code needs to be changed, so that you may be able to better understand the above comment and the original question!

Guess you like

Origin blog.csdn.net/qq_43290318/article/details/109141684