题意:摘自NOCOW翻译(http://www.nocow.cn/index.php/Translate:USACO/latin)
描述
一种正方形的数字编排
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
是一个5×5的拉丁幻方,即每个1到5的整数在每行每列都出现且出现一次。 斜体文字 写个程序计算N×N的的拉丁幻方的总数且要求第一行是:
1 2 3 4 5.......N
2<=N<=7
[编辑]格式
PROGRAM NAME: latin
INPUT FORMAT
一行包含一个整数N
OUTPUT FORMAT
只有一行,表示拉丁正方形的个数,且拉丁正方形的第一行为 1 2 3 . . . N.
[编辑]SAMPLE INPUT (file latin.in)
5
[编辑]SAMPLE OUTPUT (file latin.out)
1344
解题思路:
- 完全参考NOCOW题解“优化技巧”
代码:
/*
ID: zc.rene1
LANG: C
PROG: latin
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_N 7
int N;
int visited_row[MAX_N + 1][MAX_N + 1];
int visited_col[MAX_N + 1][MAX_N + 1];
long long total_num = 0;
int seq[MAX_N + 1];
int visited[MAX_N + 1];
int count[MAX_N + 1];
int global_index;
void GetInput(FILE *fin)
{
int i;
memset(visited_row, 0, (MAX_N + 1) * (MAX_N + 1) * sizeof(int));
memset(visited_col, 0, (MAX_N + 1) * (MAX_N + 1) * sizeof(int));
memset(count, 0, (MAX_N + 1) * sizeof(int));
seq[1] = 2;
fscanf(fin, "%d", &N);
for (i=1; i<=N; i++)
{
visited_row[i][i] = 1;
visited_col[i][i] = 1;
}
}
void GetIndex(void)
{
int i, j, len;
global_index = 2;
memset(visited, 0, (MAX_N + 1) * sizeof(int));
for (i=1; i<=N; i++)
{
if (visited[i] == 0)
{
len = 0;
j = i;
do
{
visited[j] = 1;
j = seq[j];
len++;
}while (visited[j] == 0);
if (len > global_index)
{
global_index = len;
}
}
}
}
void Search(int x, int y)
{
int i;
for (i=1; i<=N; i++)
{
if (visited_row[x][i] + visited_col[y][i] == 0)
{
if (x == 2)
{
seq[y] = i;
if (y == N)
{
GetIndex();
if (count[global_index] > 0)
{
total_num += count[global_index];
return ;
}
}
}
visited_row[x][i] = 1;
visited_col[y][i] = 1;
if (y == N)
{
if (x == N - 1)
{
count[global_index]++;
total_num++;
}
else
{
Search(x + 1, 2);
}
}
else
{
Search(x, y + 1);
}
visited_row[x][i] = 0;
visited_col[y][i] = 0;
}
}
}
int main(void)
{
FILE *fin, *fout;
int i;
fin = fopen("latin.in", "r");
fout = fopen("latin.out", "w");
GetInput(fin);
Search(2, 2);
for (i=2; i<N; i++)
{
total_num *= i;
}
if (N == 2)
{
total_num = 1;
}
fprintf(fout, "%lld\n", total_num);
return 0;
}