zoukankan      html  css  js  c++  java
  • PAT Advanced 1067 Sort with Swap(0,*) (25) [贪⼼算法]

    题目

    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

    题目分析

    已知N个任意排列的数字,要求最少交换次数对其排序(排序过程只能使用0与其他数字交换位置

    解题思路

    1. 贪心算法:如果当前数字0在i号位置,找到数字i当前所处位置,将数字0和i交换

    证明:
    由于0必须参加交换操作,因此通过该策略,每步总是可以将一个非零的数回归本位。如果用0与其他不是该位置编号的数进行交换,显然会产生一个无效操作,因为后续操作中还是需要将刚才交换的数换回本位,因此该策略能将无效操作次数(与0交换的数没有回归本位的次数)降到最小,于是最优。
    第一步: 0在7号位,因此将0与7交换,得到序列3502649781
    第二步: 0在2号位,因此将0与2交换,得到序列3520649781
    第三步: 0在3号位,因此将0与3交交换,得到序列0523649781
    第四步: 0在0号位,因此将0与一个还未在本位的数字5交换,得到序列得到序列5023649781
    第五步: 0在1号位,因此将0与1交换,得到序列5123649780
    第六步: 0在9号位,因此将0与9交换,得到序列5123640789
    第七步: 0在6号位,因此将0与6交换,得到序列5123046789
    第八步: 0在4号位,因此将0与4交换,得到序列5123406789
    第九步: 0在5号位,因此将0与5交换,得到序列0123456789
    此时序列有序,总交换次数为9次。
    //style="background-color: #FF8C00;"

    1. 定义数组int pos[N],记录数字所在位置(如:pos[i],表示数字i在pos[i]的位置)
    2. 哨兵为数字0,pos[0]=0,不一定排序已完成
      • pos[0]==0,但是排序未完成,将0需要与不在本位的数字交换(因为如果0与已回到本位的数字交换会导致交换次数变多),定义数字k初始化为1,记录当前不在本位的最小数字(避免每次都循环遍历数组,查找未回到本位的数字(复杂度为O(n^2)有两个点会超时))
      • pos[0]==0,已完成排序(如何检测已完成排序?--定义变量left记录除0以外不在自己本位数字的个数,left=0表示排序完成)

    注意点

    1. 当0回到本位时,并不一定保证数字都已回到本位。此时需要找到一个未在本位的数字与0进行交换(如果选择已在本位的数字与0交换会导致交换次数增多)

    Code

    Code 01

    #include <iostream>
    #include <string>
    using namespace std;
    int main(int argc, char * argv[]) {
    	int N,m,cnt=0;//cnt--总交换次数
    	scanf("%d",&N);
    	int pos[N]= {0};// pos[i]--数字i的位置为pos[i]
    	int left=N-1; // 除0以外不在本位的数字
    	for(int i=0; i<N; i++) {
    		scanf("%d", &m);
    		pos[m]=i; // 数字m在位置i
    		if(m==i&&m!=0)left--; // 除0以外已在本位,left--
    	}
    	int k=1; //当前最小不在本位的数字,避免0在本位但排序未完成时,每次都需要遍历数组找未在本位的数字(复杂度O(n^2)会超时)
    	while(left>0) {
    		if(pos[0]==0) { //如果排序未完成,0已回到本位,将0与最小不在本位的k进行互换
    			while(k<N) {
    				if(pos[k]!=k) { //如果k不在本位 
    					swap(pos[0],pos[k]);
    					cnt++; //无需left++,因为k本来就不再本位,0在本位但是left记录的是非0不在本位的数字个数 
    					break;
    				}
    				k++; //如果k在本位,向前找最小不在本位的k 
    			}
    		}
    		while(pos[0]!=0) { //0不在本位 
    			swap(pos[0],pos[pos[0]]);
    			left--; //有一个数字回归本位 
    			cnt++;
    		}
    	}
    	printf("%d",cnt);
    	return 0;
    }
    

    Code 02

    #include <iostream>
    #include <string>
    using namespace std;
    int main(int argc, char * argv[]) {
    	int N,m,cnt=0;
    	scanf("%d",&N);
    	int pos[N]= {0};
    	for(int i=0; i<N; i++) {
    		scanf("%d", &m);
    		pos[m]=i;
    	}
    	for(int i=0; i<N; i++) { //个人理解,这里处理不是很好,因为已遍历过的i不能保证其已回到本位
    		if(pos[i]!=i) {
    			while(pos[0]!=0) {
    				swap(pos[0],pos[pos[0]]);
    				cnt++;
    			}
    			if(pos[i]!=i) {
    				swap(pos[0],pos[i]);
    				cnt++;
    			}
    		}
    	}
    	printf("%d",cnt);
    	return 0;
    }
    
  • 相关阅读:
    强化学习的基本迭代方法
    基于文本描述的事务聚类
    学习强化学习之前需要掌握的3种技能
    其它 华硕 ASAU S4100U 系统安装 win10安装 重装系统 Invalid Partition Table 解决
    数据分析 一些基本的知识
    Python 取样式的内容 合并多个文件的样式 自定义样式
    电商 Python 生成补单公司需要的评论格式3
    SpringBlade 本地图片上传 生成缩略图
    SQL Server 字符串截取
    SpringBlade 本地图片上传
  • 原文地址:https://www.cnblogs.com/houzm/p/12244928.html
Copyright © 2011-2022 走看看