?? usaco_3_2_5_msquare_bfs找出一種排列在全排列中的位置.cpp
字號(hào):
/*
ID: wangyuc2
PROB:msquare
LANG: C++
*/
/*
這道題是BFS+Hash
在做哈希時(shí),以為8的全排列為40320,所以找到序列是全排列中第幾個(gè)元素就可以。
介紹一下字符串的一種hash 函數(shù),對這題非常有用。如果敘述不清,請參看05年集訓(xùn)隊(duì)李羽修的論文。
對于一種排列方式(可視為是一個(gè)字符串),計(jì)算它在所有排列方式中排第x位,這樣就可以做到一一對應(yīng)
。對其從右往左數(shù)的第i位進(jìn)行如下操作:
計(jì)算i位置后比第i位小的字符個(gè)數(shù)p。
x=x+(i-1)!*p。
最后,x=x+1 。
X即計(jì)算出。
用一個(gè)布爾數(shù)組used來判重,用整形數(shù)組a[40500][2]來記錄具體路徑.
我這里a[i][0]記錄的是hash值為i的魔板狀態(tài)的前一步的hash值,a[i][1]記錄從上一狀態(tài)得到hash值為i的魔板狀態(tài)的變化方法。
這樣在輸出時(shí)只需從后往前找,一直找到a[1][0]=0結(jié)束,然后逆序輸出即可。
*/
#include <fstream>
#include <iostream>
#include <string>
#include <memory>
#include <algorithm>
#include <queue>
#include <stack>
#define cin fin
using namespace std;
ifstream fin("msquare.in");
ofstream fout("msquare.out");
int power(int a)
{
int s=1;
for(int i=a;i>0;i--)
s*=i;
return s;
}
int hashf(string s)
{
int a=0,t;
for(int i=0;i<7;i++){
t=0;
for(int j=i+1;j<8;j++) if(s[j]<s[i]) t++;
a+=power(7-i)*t;
}
return ++a;
}
int main()
{
int i,j,k,n;
bool used[40500];
int a[40500][2];
char temp;
string s,st,s1;
queue<string> q;
s.assign("12345678");
memset(used,false,sizeof(used));
st.assign(s);
for(i=0;i<8;i++)
cin>>st[i];
// reverse(&st[4],st.end());
q.push(s);
used[1]=true;
a[1][0]=0;a[1][1]=0; //0為之前數(shù),1為決策
while(!q.empty())
{
s.assign(q.front());
q.pop();
k=hashf(s);
if(!s.compare(st)) break;
s1.assign(s); //A
reverse(s1.begin(),s1.end());
j=hashf(s1);
if(!used[j] && a[k][1]!=1){
q.push(s1);
used[j]=true;
a[j][0]=k;
a[j][1]=1;
}
s1[0]=s[3];s1[3]=s[2];s1[2]=s[1];s1[1]=s[0]; //B
s1[7]=s[4];s1[4]=s[5];s1[5]=s[6];s1[6]=s[7];
j=hashf(s1);
if(!used[j]){
q.push(s1);
used[j]=true;
a[j][0]=k;
a[j][1]=2;
}
s1.assign(s); //C
s1[1]=s[6];s1[2]=s[1];s1[5]=s[2];s1[6]=s[5];
j=hashf(s1);
if(!used[j]){
q.push(s1);
used[j]=true;
a[j][0]=k;
a[j][1]=3;
}
}
stack<char> S;
while(k!=0){
S.push(char(a[k][1]+64));
k=a[k][0];
}
S.pop();
fout<<S.size()<<endl;
while(!S.empty()){
temp=S.top();
S.pop();
fout<<temp;
}
fout<<endl;
return 0;
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -