PAT 1067. Sort with Swap(0,*) (25) 思路简单,优化麻烦

来源:互联网 发布:饥荒联机版网络红色 编辑:程序博客网 时间:2024/06/05 17:51

1067. Sort with Swap(0,*) (25)

时间限制
150 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

Given any permutation of the numbers {0, 1, 2,..., N-1}, it is easy to sort them in increasing order. But what if Swap(0, *) is the ONLY operation that is allowed to use? For example, to sort {4, 0, 2, 1, 3} we may apply the swap operations in the following way:

Swap(0, 1) => {4, 1, 2, 0, 3}
Swap(0, 3) => {4, 1, 2, 3, 0}
Swap(0, 4) => {0, 1, 2, 3, 4}

Now you are asked to find the minimum number of swaps need to sort the given permutation of the first N nonnegative integers.

Input Specification:

Each input file contains one test case, which gives a positive N (<=105) followed by a permutation sequence of {0, 1, ..., N-1}. All the numbers in a line are separated by a space.

Output Specification:

For each case, simply print in a line the minimum number of swaps need to sort the given permutation.

Sample Input:
10 3 5 7 2 6 4 9 0 8 1
Sample Output:

9


这题思路很容易想到,就是不停的交换0和被0占据位置的元素。如果num[0]=0了,就交换0和位置错误的元素。重复以上。但是一直超时,各种超时,超时的你怀疑思路和书写正确。最终优化到极致,就过了。

优化点核心的有两个:1:每次交换0和对应元素,等价于交换num[0]和num[0]对应元素的位置的元素。这样就不必一直查找被0占据坑位的元素在哪。

                 2:每次寻找a[i]!=i,要利用上一次的信息。不要从头找。


#include <iostream>#include<stdio.h>#include<string>using namespace std;int num[100001];int main(){    int n;    cin>>n;    for(int i=0;i<n;i++)    {       scanf("%d",&num[i]);    }    int cnt=0;      int flag;   //flag用来标记上次的查找停止位置     for(int i=1;i<n;i++)    if(num[i]!=i)        {flag=i;        break;}        int mark=1;   //用来标记是否还有元素没有进对坑        while(mark)      {         while(num[0]!=0)  //核心优化点1         {             int pp=num[0];             int tmp;              tmp=num[pp];              num[pp]=num[0];              num[0]=tmp;             cnt++;         }             mark=0;           for(int i=flag;i<n;i++)  //核心优化点2             if(num[i]!=i)                {                    flag=i;                    mark=1;                    break;                }            if(mark!=0)                {                    int tmp;                    tmp=num[flag];                     num[flag]=0;                    num[0]=tmp;                    cnt++;                }        }    cout<<cnt;}


又看到别人另外一个风骚的思路。核心原理就是
通过存放的编号和存放的数为下一个编号,最终一定可以组成一个环
用一个萝卜一个坑举例子:
坑位:0-3-2-7
萝卜:3-2-7-0
这时候你按坑位找萝卜,在以萝卜作为新坑位找萝卜,就是3-2-7-0-3 形成一个循环。那么我们通过交换就可以让萝卜回到对应坑位。
带0的环,假设长度为n,只用交换n-1次即可。萝卜0和7交换。萝卜0和2交换。萝卜0和3交换。完成。

那么对于不带0的环呢:
坑位:1-5-4-6-9
萝卜:5-4-6-9-1
我们先用萝卜0换掉其中一个萝卜。假设换掉萝卜1。然后处理方法同上,最后在把萝卜1换回来。
因为需要换进换出,所以比上面多两次。不带0的环,长度为n,需要交换n+1次。

放代码:
#include <iostream>
#include<vector>
using namespace std;
 int main()
{
  int N,index,sum,min,temp,now;
  bool Flag;
  cin >> N;
  vector<int>swapsort(N);
  for (index = 0; index < N; index++)
  {
    cin >> swapsort[index];
  }
  sum = 0;
  for (index = 0; index < N; index++)
  {     if (swapsort[index] != index)
    {
      now = index;
      Flag = false;
      min = 0;
      while (swapsort[now] != now)
      {
        if (now == 0)Flag = true;
        temp = swapsort[now];      //注意这里并不是swap(now,swapsort[now])
        swapsort[now] = now;
        now= temp;
        min++;
      }
      if (Flag)min--;
      else min++;
        sum += min;
    }
  }
  cout << sum << endl;


  return 0;
}