hiho 1233 Boxes(狀態壓縮+BFS)

題目大意:給n(n<8)個數放置在n個位置,小的數可以移動至大的數上面,反之不行。輸出使得其有序最少需要的移動次數。


最多隻有7個數,首先可以把輸入的數離散化處理一下。

對於每一個數,考慮用三位二進制數來表示其位置。那麼對於n個數,有2^(3*n)種狀態。

假設a[i]的位置爲pos[a[i]],可用pos[a[1]]*8^a[1]+pos[a[2]]*8^a[2]+pos[a[3]]*8^a[3]+……+pos[a[n]]*8^a[n]來表示每一個狀態s。

如何根據當前狀態確定某個數a[i]的位置?

設當前狀態爲s,則(s/(8^a[i]))%8即爲當前狀態下,數a[i]所在的位置pos[a[i]]。


設定了狀態,並且知道了如何從某一狀態下確定某個數的位置,就可以通過預處理,從目標位置開始bfs,得到每一個狀態到達目標位置所需步數。然後O(1)回答每個詢問了。

BFS時,枚舉一個數,其可以向左或向右放置。由於放置時只能放在比它大的數上,因此可以去判斷一下比它小的數是不是在要放置的位置上,如果在,則不放置。相當於一個剪枝。


#include<bits/stdc++.h>
using namespace std;
#define maxn 2100000
struct P{
    int x,id;
}p[7];

int ans[maxn];
bool vis[8];
queue<int> Q;

int getnum(int n)
{
    int s=0;
    for(int i=0;i<n;++i) s+=((i+1)*(1<<(3*i)));
    return s;
}

bool check(int a,int p,int s)
{
    for(int i=0;i<a;++i)
    {
        int pos=(s>>(3*i))%8;
        if(pos==p) return 0;
    }
    return 1;
}

void bfs(int n)
{
    int i,s=getnum(n);
    ans[s]=0;
    Q.push(s);
    while(!Q.empty())
    {
        s=Q.front();Q.pop();
        memset(vis,0,sizeof(vis));
        for(i=0;i<n;++i)
        {
            int pos=(s>>(3*i))%8;
            if(vis[pos]) continue;
            vis[pos]=1;
            if(pos>1&&!vis[pos-1]&&check(i,pos-1,s)){
                int tem=s-(1<<(3*i));
                if(ans[tem]==-1)
                {
                    Q.push(tem);
                    ans[tem]=ans[s]+1;
                }
            }
            if(pos<n&&!vis[pos+1]&&check(i,pos+1,s))
            {
                int tem=s+(1<<(3*i));
                if(ans[tem]==-1)
                {
                    Q.push(tem);
                    ans[tem]=ans[s]+1;
                }
            }
        }
    }
}

bool cmp1(P a,P b) {return a.x<b.x;}
bool cmp2(P a,P b) {return a.id<b.id;}

int main()
{
    int T,i,n;
    memset(ans,-1,sizeof(ans));
    for(i=1;i<=7;++i) bfs(i);
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(i=0;i<n;++i) {scanf("%d",&p[i].x);p[i].id=i;}
        sort(p,p+n,cmp1);
        for(i=0;i<n;++i) p[i].x=i;
        sort(p,p+n,cmp2);
        int s=0;
        for(i=0;i<n;++i) s+=((i+1)*(1<<(3*p[i].x)));
        printf("%d\n",ans[s]);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章