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

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值