Vijos1029[晴天小猪历险记之Number] 搜索+康托展开

康托展开:

康托展开表示的是当前n个元素排列在n个不同元素的全排列中的名次。
比如213在这3个数所有排列中排第3。
那么,对于n个数的排列,康托展开为:
ans=an*(n-1)!+an-1*(n-2)!+…+ai*(i-1)!+…+a2*1!+a1*0!
其中:a从右向左排号 2是a3, 1是a2, 3是a1
a表示每一个数的右边比它小的数的个数
2: 13 1<2 a3=1
1: 3 a2=0
3: a1=0

#include <map>
#include <set>
#include <queue>
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
struct Matrix{
    int m[4][4], step;
}sta;

int dx[3]={0,1}, dy[3]={1,0};
int f[10]={0,40320,5040,720,120,24,6,2,1};
int vis[500005];
set<int> ans;

int Contor( Matrix s ){
    int ans=0;
    for ( int i=1; i<=9; i++ ){
        int tmp=0;
        for ( int j=i+1; j<=9; j++ )
            if( s.m[((i-1)/3)+1][((i-1)%3)+1] > s.m[((j-1)/3)+1][((j-1)%3)+1] ) tmp++;
        ans+=tmp*f[i]; 
    }
    return ans;
}



void bfs(){
    queue<Matrix> Q;
    memset(vis,0,sizeof(vis));
    vis[Contor(sta)]=1;
    sta.step=0;
    Q.push(sta);
    while( !Q.empty() ){
        Matrix u=Q.front();
        Q.pop();
        if( ans.count(Contor(u)) ){
            printf("%d\n", u.step );
            return ;
        }
        for ( int i=1; i<=3; i++ ){
            for ( int j=1; j<=3; j++ ){
                for ( int k=0; k<=1; k++ ){
                    int i0=i+dx[k];
                    int j0=j+dy[k];
                    if( i0<=3 && j0<=3 ){
                        Matrix u1=u;
                        swap( u1.m[i][j], u1.m[i0][j0] );
                        int ct=Contor(u1);
                        u1.step++;
                        if( vis[ct] ) continue;
                        vis[ct]=1;
                        Q.push(u1);
                    }
                }
            }
        }
    }
    puts("-1");
}
int main(){
    ans.clear();
    ans.insert(69074); ans.insert(77576); ans.insert(135289); ans.insert(157120);
    ans.insert(205759); ans.insert(227590); ans.insert(285303); ans.insert(293805);
    while( scanf("%d%d%d", &sta.m[1][1], &sta.m[1][2], &sta.m[1][3])==3 ){
        for ( int i=2; i<=3; i++ )
            for ( int j=1; j<=3; j++ )
                scanf("%d", &sta.m[i][j] );
        bfs();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值