hiho 1233 Boxes(状态压缩+BFS)

来源:互联网 发布:centos下制作u盘启动 编辑:程序博客网 时间:2024/05/16 03:12

题目大意:给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 2100000struct 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;}


0 0