《算法》第二章——Nuts and bolts(螺絲和螺帽)

題目:

Nuts and bolts. (G. J. E. Rawlins). You have a mixed pile of N nuts and N bolts and need to quickly find the corresponding pairs of nuts and bolts. Each nut matches exactly one bolt, and each bolt matches exactly one nut. By fitting a nut and bolt together, you can see which is bigger. But it is not possible to directly compare two nuts or two bolts. Given an efficient method for solving the problem.

Hint: customize quicksort to the problem. Side note: only a very complicated deterministic O(N log N) algorithm is known for this problem.


思路:

標準的快排啊, 用螺母把螺絲分區,每次分區得到三個結果,
A1,完全匹配的一對
A2,比螺母小的螺絲
A3,比螺母大的螺絲
將1中的螺絲取出,用它對螺母分區,可以得到
B1. 比螺絲小的螺母
B2. 比螺絲大的螺母
A2跟B1一一對應,A3跟B2一一對應,對(A2,B1)和(A3,B2)分別執行上述的算法,直至完全匹配。

代碼:

/*假設螺釘和螺帽大小沒有一樣的。
    每次取nuts數組中最後一個元素到bolts數組中去找和它配對的元素,這樣可以避免nuts數組中後部元素前移。*/
#include<iostream>
using namespace std;

int partition(int *nuts,int *bolts,int lo,int hi)
{//爲了保證操作nuts和bolts數組的一致性,將每次配對成功的元素放在hi的位置。
  int nuts_t = nuts[hi];
  int i=lo;
  int j=hi;
  int bolt_match=0;

  while(true)
  {//在bolts中找到配的nuts並將bolts分區
    while(bolts[i] <= nuts_t)
    {
      if(nuts_t == bolts[i])
      {//先判斷匹配的情況——找到完全相同的一對
        bolt_match = bolts[i];
        cout<<nuts_t<<"&"<<bolts[i]<<endl;
        for(int k = i + 1;k <= hi;k++)
        {//把當前匹配的元素位置通過後面的元素前移一格的方式填充
          bolts[k -1] = bolts[k];
        }

        j--;//j一定指向後面要移動的某個元素,所以需要跟着遞減1
        hi--;//數組長度減1

//        for(int k=lo;k<=hi;k++)
//          cout<<bolts[k]<<" ";
//        cout<<endl;

       // i++;這裏不需要指針後移
        if(i > hi)//別越界
          break;
      }
      else
      {
        i++;
        if(i > hi)//別越界
          break;
      }
    }//從左往右找到第一個大的螺釘

    while(bolts[j] >= nuts_t)
    {
      if(nuts_t == bolts[j])
      {//先判斷匹配的情況
        bolt_match = bolts[j];
        cout<<nuts_t<<"&"<<bolts[j]<<endl;
        for(int k = j + 1;k <= hi;k++)
        {//把當前匹配的元素位置通過後面的元素前移一格的方式填充
          bolts[k -1] = bolts[k];
        }
        hi--;
        j--;//j指針前移

//        for(int k=lo;k<=hi;k++)
//          cout<<bolts[k]<<" ";
//        cout<<endl;

        if(j < lo)//別越界
          break;
      }
      else
      {
        j--;
        if(j < lo)//別越界
          break;
      }
    }//從右往左找到第一個小的螺釘

    if(i >= j)//數組掃描過一遍
    {
      if(i == j)
        cout<<"error"<<endl;
      break;
    }
    int tmp = bolts[i];//交換
    bolts[i] = bolts[j];
    bolts[j] = tmp;
  }

//  for(int k=lo;k<=hi;k++)
//    cout<<bolts[k]<<" ";
//  cout<<endl;


  i = lo;
  j = hi;
  while(true)
  {//用上面bolts數組中找到的配對的螺釘,將nuts分區
    while(nuts[i] < bolt_match)
    {
      i++;
      if(i > hi)//別越界
        break;
    }
    while(nuts[j] > bolt_match)
    {
      j--;
      if(j < lo)//別越界
        break;
    }
    if(i > j)
      break;
    int tmp = nuts[i];//交換
    nuts[i] = nuts[j];
    nuts[j] = tmp;
  }
//  for(int k=lo;k<=hi;k++)
//    cout<<nuts[k]<<" ";
//  cout<<endl;

  return i;//第一個比較大的元素
}

void sort(int *nuts,int *bolts,int lo,int hi)
{
  if(lo == hi)
  {
    cout<<nuts[hi]<<"&"<<bolts[hi]<<endl;
    return;
  }
  else if(lo > hi)
  {
    return;
  }
  int j = partition(nuts,bolts,lo,hi);
  hi--;//經過一次劃分後會成功配對一次,相應的hi要減一
//  cout<<"j->"<<j<<endl;
//  cout<<"lo->"<<lo<<endl;
//  cout<<"hi->"<<hi<<endl;
  sort(nuts,bolts,lo,j-1);
  sort(nuts,bolts,j,hi);
}

int main()
{
  int nuts[10] = {1,3,2,4,6,5,7,9,8,0};
  int bolts[10] = {7,4,1,8,5,2,9,6,3,0};

  sort(nuts,bolts,0,9);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章