标签:tee mes title tps swa amp cas turn mini
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 130000/65536 K (Java/Others)
Total Submission(s): 4621 Accepted Submission(s): 1006
康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的。
以下称第x个全排列是都是指由小到大的顺序。
康拓展开式
\[X=a_{n}\left ( n-1 \right )!+a_{n-1}\left ( n-2 \right )!+\cdots a_{1}\cdot 0!\]
例如,3 5 7 4 1 2 9 6 8 展开为 98884。因为X=2*8!+3*7!+4*6!+2*5!+0*4!+0*3!+2*2!+0*1!+0*0!=98884.
解释:
排列的第一位是3,比3小的数有两个,以这样的数开始的排列有8!个,因此第一项为2*8!
排列的第二位是5,比5小的数有1、2、3、4,由于3已经出现,因此共有3个比5小的数,这样的排列有7!个,因此第二项为3*7!
以此类推,直至0*0!
用途
显然,n位(0~n-1)全排列后,其康托展开唯一且最大约为n!,因此可以由更小的空间来储存这些排列。由公式可将X逆推出唯一的一个排列。
code
static const int FAC[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880}; // 阶乘 int cantor(int *a, int n) { int x = 0; for (int i = 0; i < n; ++i) { int smaller = 0; // 在当前位之后小于其的个数 for (int j = i + 1; j < n; ++j) { if (a[j] < a[i]) smaller++; } x += FAC[n - i - 1] * smaller; // 康托展开累加 } return x; // 康托展开值 }
#include<iostream> #include<cstdio> #include<cstdlib> #include<sstream> #include<cstring> #include<string> #include<vector> #include<set> #include<stack> #include<queue> #include<map> #include<cmath> #include<algorithm> using namespace std; #define inf 0x3f3f3f3f #define ll long long #define MAX_N 362882 + 10 #define gcd(a,b) __gcd(a,b) #define mem(a,x) memset(a,x,sizeof(a)) #define mid(a,b) a+b/2 #define stol(a) atoi(a.c_str())//string to long int fac[10]; int beg[10][10] ={{0, 1, 2, 3, 4, 5, 6, 7, 8},{1, 0, 2, 3, 4, 5, 6, 7, 8},{1, 2, 0, 3, 4, 5, 6, 7, 8},{1, 2, 3, 0, 4, 5, 6, 7, 8},{1, 2, 3, 4, 0, 5, 6, 7, 8},{1, 2, 3, 4, 5, 0, 6, 7, 8},{1, 2, 3, 4, 5, 6, 0, 7, 8},{1, 2, 3, 4, 5, 6, 7, 0, 8},{1, 2, 3, 4, 5, 6, 7, 8, 0}}; int dir[5][2] = {{1,0},{0,-1},{0,1},{-1,0}}; char operate[5] = "dlru"; int c; int cal_cantor(int a[]){ int ans = 0; for (int i = 0; i < 9; i++){ int temp = 0; for (int j = i + 1; j < 9; j++){ if (a[j] < a[i]){ temp++; } } ans += temp * fac[8 - i]; } return ans; } int temp[10]; int mark[10]; int start_cantor[10]; struct Node{ int a[10]; int x; }; struct Vis{ int pre; char p; int step; }vis[10][MAX_N]; void bfs(int t,Node node){ queue<Node> que; que.push(node); while(que.size()){ Node n = que.front(); que.pop(); int n_contor = cal_cantor(n.a); int pos = n.x; for(int i = 0; i < 4; i++){ int x = n.x/3; int y = n.x%3; int nx = x + dir[i][0]; int ny = y + dir[i][1]; if(nx >= 0 && nx < 3 && ny >= 0 && ny < 3){ int cnt = nx * 3 + ny; swap(n.a[cnt],n.a[pos]); n.x = cnt; int v = cal_cantor(n.a); if(vis[t][v].pre == -1&&v!=start_cantor[t]){ vis[t][v].pre = n_contor; vis[t][v].p = operate[i]; vis[t][v].step = vis[t][n_contor].step + 1; que.push(n); } n.x = pos;// swap(n.a[cnt],n.a[pos]); } } } } void init(){ fac[0] = fac[1] = 1; for (int i = 2; i < 10; i++){ fac[i] = fac[i - 1] * i; } for(int i = 0; i < 9; i++){ for(int j = 0; j < MAX_N;j++) vis[i][j].pre = -1; } Node node; for(int i = 0; i < 9; i++){ swap(node.a,beg[i]); node.x = i; start_cantor[i] = cal_cantor(node.a); bfs(i,node); swap(node.a,beg[i]); } } int main(){ //std::ios::sync_with_stdio(false); //std::cin.tie(0); #ifndef ONLINE_JUDGE freopen("D:\\in.txt","r",stdin); freopen("D:\\out.txt","w",stdout); #else #endif init(); int T; scanf("%d",&T); string str; int t = 0; while(T--){ cin >> str; for(int i = 0; i < 9; ++i){ temp[i] = (str[i] == ‘X‘? 0 : str[i]-‘0‘); if(str[i] == ‘X‘) c = i; } for(int i = 0; i < 9; ++i){ mark[temp[i]] = beg[c][i]; } cin >> str; for(int i = 0; i < 9; ++i){ temp[i] = (str[i] == ‘X‘? 0 : str[i]-‘0‘); temp[i] = mark[temp[i]]; } Node n; swap(n.a,temp); int end_ = cal_cantor(n.a); printf("Case %d: %d\n",++t,vis[c][end_].step); string ans = ""; while(vis[c][end_].step!=0){ ans = vis[c][end_].p + ans; end_ = vis[c][end_].pre; } cout<<ans<<endl; } return 0; }
标签:tee mes title tps swa amp cas turn mini
原文地址:https://www.cnblogs.com/zaorunzi/p/9862596.html