Magic Squares USACO 3.2 (康托展开)

容易想到bfs,然后是根据重复剪枝,问题是如何判重复,若把每次访问过的字符串看成数作为index,最大有87654321,

而实际只有8!阶乘个数,大致40000多点。

这里要用到

康托展开

应用实例

{1,2,3,4,...,n}表示1,2,3,...,n的排列如 {1,2,3} 按从小到大排列一共6个。123 132 213 231 312 321 。
代表的数字 1 2 3 4 5 6 也就是把10进制数与一个排列对应起来。
他们间的对应关系可由康托展开来找到。
如我想知道321是{1,2,3}中第几个小的数可以这样考虑 :
第一位是3,当第一位的数小于3时,那排列数小于321 如 123、 213 ,小于3的数有1、2 。所以有2*2!个。再看小于第二位2的:小于2的数只有一个就是1 ,所以有1*1!=1 所以小于321的{1,2,3}排列数有2*2!+1*1!=5个。所以321是第6个小的数。 2*2!+1*1!+0*0!就是康托展开。
再举个例子:1324是{1,2,3,4}排列数中第几个大的数:第一位是1小于1的数没有,是0个 0*3! 第二位是3小于3的数有1和2,但1已经在第一位了,所以只有一个数2 1*2! 。第三位是2小于2的数是1,但1在第一位,所以有0个数 0*1! ,所以比1324小的排列有0*3!+1*2!+0*1!=2个,1324是第三个小数。
 
所以每个数可以展开为该数在整个排列集合里第几小来判重
 
 1 int CantorHash(string & str)
 2 {
 3     int hash_index=0;
 4     for(int i=0;i<str.length();i++)
 5     {
 6         int temp=0;
 7         for(int j=i+1;j<str.length();j++)
 8         {
 9     
10             if(str[i]>str[j])
11                 temp++;
12         }
13         hash_index+=temp*FRAC[7-i];
14     }
15     return hash_index+1;
16 }

最后+1是因为hash_index表示比当前数小的数的个数。

/*

ID: hubiao cave

PROG: msquare

LANG: C++

*/




#include<iostream>

#include<fstream>

#include<string>
#include<deque>

using namespace std;


void Afunc(string&);
void Bfunc(string&);
void Cfunc(string&);

bool gVisted[44000];
const int FRAC[8]= {1, 1, 2, 6, 24, 120, 720, 5040};

int CantorHash(string & str)
{
    int hash_index=0;
    for(int i=0;i<str.length();i++)
    {
        int temp=0;
        for(int j=i+1;j<str.length();j++)
        {
    
            if(str[i]>str[j])
                temp++;
        }
        hash_index+=temp*FRAC[7-i];
    }
    return hash_index+1;
}

int main()

{


    ifstream fin("msquare.in");

    ofstream fout("msquare.out");
    
    typedef deque<pair<string,string> >Queues;
    Queues str_queue;
    string goal_string;
    string original_string="12345678";
    string temp_string;
    char ch;
    while(fin>>ch)
    {
        goal_string+=ch;
    }

    str_queue.push_back(make_pair(original_string,""));
    while(str_queue.size()!=0)
    {
        pair<string,string> p=str_queue.front();
        str_queue.pop_front();
        temp_string=p.first;
        int hashindex=CantorHash(p.first);
        if(gVisted[hashindex])
            continue;
        else
        {
            gVisted[hashindex]=true;
        }

        if(p.first==goal_string)
        {
            fout<<p.second.size()<<endl;
            fout<<p.second<<endl;
            return 0;
        }
        else
        {
            string temp=temp_string;
            Afunc(temp);
            str_queue.push_back(make_pair(temp,p.second+'A'));
    
            temp=temp_string;
            Bfunc(temp);
            str_queue.push_back(make_pair(temp,p.second+'B'));


            temp=temp_string;
            Cfunc(temp);
            str_queue.push_back(make_pair(temp,p.second+'C'));
    

        }
    }
    return 0;


}
void Afunc(string& pstr)
{
    for(int i=0;i<4;i++)
    {
        char ch=pstr[i];
        pstr[i]=pstr[7-i];
        pstr[7-i]=ch;
    }
}

void Bfunc(string& pstr)
{
    char ch1=pstr[3],ch2=pstr[4];
    pstr[3]=pstr[2],pstr[4]=pstr[5];
    pstr[2]=pstr[1],pstr[5]=pstr[6];
    pstr[1]=pstr[0],pstr[6]=pstr[7];
    pstr[0]=ch1,pstr[7]=ch2;
}

void Cfunc(string& pstr)
{
    char ch=pstr[2];
    pstr[2]=pstr[1];
    pstr[1]=pstr[6];
    pstr[6]=pstr[5];
    pstr[5]=ch;
}

 

posted @ 2013-10-09 08:31  cavehubiao  阅读(264)  评论(0编辑  收藏  举报