• [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;
    }
    
  • 相关阅读:
    Linux下汇编语言学习笔记31 ---
    Linux下汇编语言学习笔记30 ---
    Linux下汇编语言学习笔记27 ---
    Linux下汇编语言学习笔记26 ---
    Linux下汇编语言学习笔记25 ---
    设计模式 关注点分离
    设计模式 关注点分离
    ALAsset和ALAssetRepresentation详解
    ALAsset和ALAssetRepresentation详解
    VIEW当中自定义属性的使用
  • 原文地址:https://www.cnblogs.com/nosta/p/9780428.html
Copyright © 2020-2023  润新知