USACO Training Section 2.1 Sorting a Three-Valued Sequence

英文原题  中文题译 
题目大意是:给定一个由数字123构成的数列,最少多少次交换可以使得其变成升序序列。

以前做过POJ上的USACO题中有类似的,大意是给定123的序列,不交换,但可改变数字的值,问至少要改变多少个值使得整个序列有序。比这个略难些。对此题,扫描整个数列,得到每个数字区间的位置,考虑到首先所有的在23区间的1必须交换回1区间,然后考虑这样的交换会导致多少3跑到区间2中。注意n_i_j中存在一些等式,所以计算不难。

可将此题推广,在长为N的序列中有M个数,最少多少交换可使得序列变成升序。这样,第一部分基本不变,需要N×M的数组来记录数字位置,如果N×M很大,则可以两次扫描,第一次扫描得到每个数字的位置,第二次扫描用M×M数组(M×(M-1)/2就够)存放错位情况即:数字j在区间i中出现的个数。然后M循环,首先把数字1放在区间1内,逐个更新余下的错位数,然后数字2,....。算法的时间复杂度为O(N*M+M^3),考虑到一般M<<N,故依然为O(N*M),不过编程复杂度集中在后部。

/*
ID: blackco3
TASK: sort3
LANG: C++
*/
#include <fstream>
using namespace std;
#define _max_ 1000
int main() {	
	ifstream fin("sort3.in");
	ofstream fout("sort3.out");
	int n_digit, n_dig[3]={0, 0, 0}, count[3][_max_+1]={{0}, {0}, {0}}, cur ;
	fin >> n_digit ;
	for( int i=1; i<=n_digit; i++ ){
		fin >> cur ;
		for( int j=0; j<3; j++){
			count[j][i] = count[j][i-1] + (j==cur-1)  ;
			n_dig[j] +=	(j==cur-1) ;
		}
	}
	int n21=count[1][n_dig[0]]; /* how many 2 in segment 1 */
	int n31=count[2][n_dig[0]]; /* how many 3 in segment 1 */
	int n12=count[0][n_dig[0]+n_dig[1]]-count[0][n_dig[0]]; /* how many 1 in segment 2 */
	int n32=count[2][n_dig[0]+n_dig[1]]-count[2][n_dig[0]]; /* how many 3 in segment 2 */
	fout << (n21 + n31) + (n32 + n12 - (n12<n21 ? n12 : n21)) << endl ;
	return 0;
}

你可能感兴趣的:(算法,J#,asp)