首页 > 代码库 > USACO 6.5 All Latin Squares

USACO 6.5 All Latin Squares

All Latin Squares

A square arrangement of numbers

1  2  3  4  5
2  1  4  5  3
3  4  5  1  2
4  5  2  3  1
5  3  1  2  4

is a 5 x 5 Latin Square because each whole number from 1 to 5 appears once and only once in each row and column.

Write a program that will compute the number of NxN Latin Squares whose first row is:

1 2 3 4 5.......N

Your program should work for any N from 2 to 7.

PROGRAM NAME: latin

INPUT FORMAT

One line containing the integer N.

SAMPLE INPUT (file latin.in)

5

OUTPUT FORMAT

A single integer telling the number of latin squares whose first row is 1 2 3 . . . N.

SAMPLE OUTPUT (file latin.out)

1344

————————————————————题解
第一行已经固定了,如果我们固定第一列为1 2 3 4 5……n 那么我们计算出的方案数乘以(n-1)!即可
然后这个优化加上位运算也只能过6。7就很尴尬了。
还有一个神一般的优化
例如
1 2 3 4 5
2 1 4 3 5
这其中有两个置换圈 1,2 和 3,4,5
如果再来一种搜索搜到了
1 2 3 4 5
2 3 1 5 4
这其中有两个置换圈 1 2 3 和 4 5
注意到了吗这个置换圈要先从大到小排序
这样的话其实这两种情况是等价的
为什么等价?
长度为2的两个圈 1 2 和 4 5可以分别一一对应
长度为3的两个圈3 4 5 和 1 2 3可以分别一一对应
也就是像我们手里得到了一张转换表,把第一种情况里的后四排的
1写成4
2写成5
3写成1
4写成2
5写成3
最后得到了一个新的拉丁方格
所以我们用一个哈希表记录置换圈的长度和所有置换圈长度的乘积,算过一遍的方案直接得出,节省很多时间……
orz反正我是想不到的
 1 /*
 2 LANG: C++
 3 PROG: latin
 4 */
 5 #include <iostream>
 6 #include <cstdio>
 7 #include <algorithm>
 8 #include <cstring>
 9 #include <cmath>
10 #define siji(i,x,y) for(int i=(x); i<=(y) ; ++i)
11 #define ivorysi
12 #define o(x) ((x)*(x))
13 using namespace std;
14 typedef long long ll;
15 int n;
16 int col[10],row[10],num[10][10];
17 bool v[10];
18 ll ans,h[50][5];//置换圈的长度乘积,个数
19 void init() {
20     scanf("%d",&n);
21     siji(i,1,n) {
22         num[1][i]=i;
23         num[i][1]=i;
24         col[i]=(1<<i);
25         row[i]=(1<<i);
26     }
27     memset(h,-1,sizeof(h));
28 }
29 
30 ll dfs(int x,int y) {
31     if(x>=n){
32         return 1;
33     }
34     ll res=0;
35     if(x==3&&y==2) {
36         memset(v,0,sizeof(v));
37         int cnt=0,len=1;
38         siji(i,1,n) {
39             if(v[i]) continue;
40             v[i]=1;
41             int rec=1;
42             for(int l=num[2][i];l!=i;l=num[2][l]) {
43                 v[l]=1;
44                 ++rec;
45             }
46             len*=rec;
47             ++cnt;
48         }
49         if(h[len][cnt]!=-1) return h[len][cnt];
50         siji(i,1,n) {
51             if(((col[y]&(1<<i))==0) && ((row[x]&(1<<i))==0)) {
52                 col[y]|=(1<<i);
53                 row[x]|=(1<<i);
54                 num[x][y]=i;
55                 if(y==n) res+=dfs(x+1,2);
56                 else res+=dfs(x,y+1);
57                 col[y]^=(1<<i);
58                 row[x]^=(1<<i);
59                 num[x][y]=0;
60             }
61         }
62         return h[len][cnt]=res;
63     }
64     siji(i,1,n) {
65         if(((col[y]&(1<<i))==0) && ((row[x]&(1<<i))==0)) {
66             col[y]|=(1<<i);
67             row[x]|=(1<<i);
68             num[x][y]=i;
69             if(y==n) res+=dfs(x+1,2);
70             else res+=dfs(x,y+1);
71             col[y]^=(1<<i);
72             row[x]^=(1<<i);
73             num[x][y]=0;
74         }
75     }
76     return res;
77 }
78 void solve() {
79     init();
80     //if(n==7) {cout<<"12198297600"<<endl;return;}
81     ans=dfs(2,2);
82     siji(i,1,n-1) ans*=i;
83     printf("%lld\n",ans);
84 }
85 int main(int argc, char const *argv[])
86 {
87 #ifdef ivorysi
88     freopen("latin.in","r",stdin);
89     freopen("latin.out","w",stdout);
90 #else
91     freopen("f1.in","r",stdin);
92     //freopen("f1.out","w",stdout);
93 #endif
94     solve();
95     return 0;
96 }

 

USACO 6.5 All Latin Squares