题目
解题说明
开始看题时,觉的就是一道全排列的题目,只要通过dfs加上固定的搜索次数即可,但看了眼数据,好家伙10000,那么100009999…肯定得超时,但是我还是不信邪写出了dfs方法,结果并不理想。
方法二:仔细观察题目后,发现这道题竟然有些贪心的影子,每一次求出最佳位置就好了。
比如,1 2 3 4 5,这个五个数字进行一次变换,在1 2 3 4 5 的基础上求出变换的最小值。
是不是开始熟悉了,1 2 3 4 5 他的下一次变换最小值为 1 2 3 5 4 怎么来的?
我们可以模拟找出第一个第n项大于第n-1项的数,不过一定是从后往前找。 1 2 3 4 5 很显然, n==5时成立
然后从n开始寻找,寻找从n开始的片段中比n-1大的数,在这个片段中最小的数。
然后把从n开始的片段的数字,从小到大开始排序。
叉叉代码(DFS超时典例)
代码如下:
import java.util.Scanner;
public class P1088 {
private static int[] arr;
private static int[] brr;
private static boolean[] is;
private static int cnt=-1;
private static int M;
private static boolean flag=false;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int N=sc.nextInt();
M=sc.nextInt();
arr=new int[N+1];brr=new int[N+1];is=new boolean[N+1];
for (int i = 0; i <N+1 ; i++) is[i]=true;
for (int i = 1; i <N+1 ; i++) arr[i]=sc.nextInt();
dfs(1,N);
}
static void dfs(int index,int N){
if(flag){
return;
}
if(index>N ){
cnt++;
if(cnt==M)
{
for (int i = 1; i < brr.length; i++)
{
flag=true;
if(i!=brr.length-1)
{
System.out.print(brr[i]+" ");
}else {
System.out.print(brr[i]);
}
}
return;
}
return;
}
for(int i = 1; i <=N ; i++) {
if(is[i]){
brr[index]=arr[i];
is[i]=false;
dfs(index+1,N);
is[i]=true;
}
}
}
}
AC代码
代码如下:
import java.util.Scanner;
public class P1088_plus {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(),m=sc.nextInt();
int[] arr=new int[n+1];
for (int i = 1; i <arr.length ; i++) arr[i]=sc.nextInt();
int j,k=0;
for (int i = 0; i <m ; i++) {
for ( j = n; j >=1 ; j--) {
if(arr[j]>arr[j-1]){
break;
}
}
j--;
for (k = n; k>j ; k--) {
if(arr[j]<arr[k] ){
break;
}
}
swap(arr,j,k);
j++; k=n;
while(j<k){
swap(arr,j,k);
j++;
k--;
}
}
for (int i = 1; i < n+1; i++) {
if(i!=n)
{
System.out.print(arr[i]+" ");
}else{
System.out.print(arr[i]);
}
}
}
static void swap(int[] arr,int m,int n){
int temp=arr[m];
arr[m]=arr[n];
arr[n]=temp;
}
}