[NOIP模拟赛] 序列

Description

给定一个1n的排列x,每次你可以将x1xi翻转。你需要求出将序列变为升序的最小操作次数。有多组数据。

Input

第一行一个整数t表示数据组数。

每组数据第一行一个整数n,第二行n个整数x1~xn。

Output

每组数据输出一行一个整数表示答案。

Sample Input

1

8

8 6 1 3 2 4 5 7

Sample Output

7

Data Constraint

对于100%的测试数据,t=5,n<=25。

对于测试点1,2,n=5。

对于测试点3,4,n=6。

对于测试点5,6,n=7。

对于测试点7,8,9,n=8。

对于测试点10,n=9。

对于测试点11,n=10。

对于测试点i (12<=i<=25),n=i。

Solution

容易发现,对于长度为n的排列最多翻转2*n-2次可得到升序排列。故本题采用带估价的ID算法。估价函数设计为满足|c[i]-c[i+1]|>1的i的个数(令c[n+1]=n+1)。

Code

#include <bits/stdc++.h>
using namespace std;
char ch;
template<typename _Type> inline
	void read(_Type&d) {
 		d=0, ch=getchar();
 		while(!isdigit(ch)) ch=getchar();
 		do d=d*10+ch-'0', ch=getchar();
 		while(isdigit(ch));
	}

const int N=30;

int T,n,ans;
int b[N],c[N];

bool dfs(int n,int use) {
	if(use>ans) return 0;
	while(n && c[n]==n) n--;
	if(!n) return 1;
	int gue=0;
	for(int i=1; i<=n; ++i) 
		gue+=(abs(c[i]-c[i+1])>1);
	if(use+gue>ans) return 0;
	bool well=false;
	for(int i=2; i<=n; ++i) {
		reverse(c+1,c+i+1);
		well=dfs(n, use+1);
		reverse(c+1,c+i+1);
		if(well) break;
	}
	return well;
}

int main() {
	read(T);
	while(T--) {
		read(n);
		for(int i=1; i<=n; ++i) read(c[i]);
		while(n && c[n]==n) n--;
                c[n+1]=n+1;
		for(ans=0; ans<=2*n-2; ++ans) {
			if(dfs(n,0)) break;
		}
		printf("%d
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/nosta/p/9780428.html