现在的位置: 首页 > 综合 > 正文

简单的BFS 和康托展开式的应用

2017年11月15日 ⁄ 综合 ⁄ 共 1573字 ⁄ 字号 评论关闭

Description:

给n的某种排列和k,问最少次操作可以将n的这个全排列变成1~n。

每次操作可以选择连续k个数,然后将它们翻转。

Input

第一行输入一个数T,表示测试数据个数

对于每组数据,第一行输入两个数n,k,然后第二行输入n个数,为1~n的某种排列。

数据范围:(1<=k<=n<=8)

Output

对于每组数据输出一个数,表示最少的操作次数,如果无法完成,输出-1.

Sample Input

3

3 3

1 2 3

3 3

3 2 1

5 4

3 2 4 5 1

Sample Output

0

1

-1

思路分析:1.最少的步骤数,很容易想到BFS,

                   2.主要是 状态如何存储,最多有8!=40320个排列,可以用康托展开式来存储,n!个排列对应数0-n!-1,就很方便记忆状态了

注意:1.queue用之前要清空

#include<iostream>
#include<cstdio>
#include<queue>
#include<memory.h>
using namespace std;
int n,k;
struct node
{
    int arr[9];
    int step;
};
bool flag[100000];

queue<node>q;

int fun(int x)//求阶乘
{
    if(x==1||x==0)
        return 1;
    else
    {
         int sum=1;
         for(int i=x;i>=1;i--)
            sum*=i;
         return  sum;
    }
}
int cantor(node x)//求康托相对应的数
{
    int sum=0;
    /*for(int i=1;i<=n;i++)
        printf("%d**",x.arr[i]);*/
    for(int i=1;i<=n;i++)
    {
        int temp=0;
        for(int j=i+1;j<=n;j++)
            if(x.arr[j]<x.arr[i])
                temp++;
        sum+=temp*fun(n-i);
    }
    //printf("sum=%d\n",sum);
    return sum;
}
void inline swap(int &x,int &y)
{
    int temp=x;
    x=y;
    y=temp;
}
node shift(node x,int i)
{
    for(int j=1;j<=k/2;j++)
        swap(x.arr[i+j-1],x.arr[i+k-1-j+1]);
    return x;
}
int main()
{
    int T;
    node a;
    scanf("%d",&T);
    while(T--)
    {
        memset(flag,0,sizeof(flag));
        int ans=0;
        scanf("%d %d",&n,&k);
        for(int i=1;i<=n;i++)
            scanf("%d",&a.arr[i]);
        a.step=0;
        while(!q.empty())//忘了清空队列
            q.pop();
        q.push(a);
        /*for(int i=1;i<=n;i++)
            printf("%d   ",a.arr[i]);*/
        int x=cantor(a);
        //printf("x=%d\n",x);
        flag[x]=1;
        if(x==0)
           {
               printf("0\n");
               continue;
           }
        int ok=0;
        while(!q.empty())
        {
            node temp=q.front();
            q.pop();
            for(int i=1;i<=n-k+1;i++)//弄成i-k+1
            {
                node t=shift(temp,i);
                t.step=temp.step+1;
                x=cantor(t);
                if(x==0)
                {
                    ok=1;
                    ans=t.step;
                    break;
                }
                if(flag[x]==1)//出现过的状态 标记一下,避免再次遍历
                    continue;
                else
                {
                    flag[x]=1;
                    q.push(t);
                }
            }
            if(ok==1)
                break;
        }
        if(ok==0)
           ans=-1;
        printf("%d\n",ans);
    }
    return 0;
}

 

抱歉!评论已关闭.