Здравствуйте. Мне дали такое задание:
Необходимо подсчитать количество латинских квадратов, ортогональных данному:
0572164938
6051298473
4867039215
1439807652
8324756091
7203941586
5610473829
9148625307
2795380164
3986512740
То есть, мне нужно написать программу на С, которая будет находить ортогональные квадраты.
Я пытался что-то сделать и пришел к выводу, что программа должна сразу генерировать квадраты ортогональными основному квадрату, вроде бы такой метод используется в народе, но как все это реализовать я не знаю. Да и формулу я найти не смог. Помогите пожалуйста!!
Другие языки программирования и технологии
Язык С. Помогите построить ортогональные латинские квадраты.
Такой вариант построения ортогональных квадратов.
#include <stdio.h>
#include <conio.h>
#define n 10
#define mask ~((-1) << n)
#define border (1 << n)
char s[n][n] = {{"0572164938"}, {"6051298473"}, {"4867039215"},
{"1439807652"}, {"8324756091"}, {"7203941586"}, {"5610473829"},
{"9148625307"}, {"2795380164"}, {"3986512740"}};
int q[n][n], a[n][n];
int p[n * n];
long long m = 0;
void solution(int, int);
int main()
{
int i, j;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
{
q[i][j] = 1 << (s[i][j] -= '0');
a[i][j] = border;
}
solution(0, 0);
printf("Ортогональных латинских квадратов: %d%09d\n", (int)(m / 1000000000), (int)(m % 1000000000));
getch();
return 0;
}
void solution(int i, int j)
{
int k, t, r, v, set = 0;
for (k = 0; k < i || k < j; k++)
set |= a[i][k] | a[k][j];
for (k = 1; (set & mask) != mask && !(k & border); k <<= 1)
if (!(set & k))
{
v = q[i][j] << 2 * n | k;
for (t = i * n + j - 1; t >= 0; t--)
if (p[t] == v) break; // <========
if (t < 0)
{
t = i;
r = j >= n - 1? t++, r = 0 : j + 1;
if (t >= n) m++;
else
{
p[i * n + j] = v;
a[i][j] = k;
solution(t, r);
a[i][j] = border;
}
}
}
}
Для хотя бы какого-то ускорения, построение идет бинарными полями. Поэтому, если потребуется выводить полученные квадраты, придётся их предварительно декодировать.
Для порядков n = 3, 4, 5, 7 получено соответственно 6, 48, 360, 3200400 ортогональных квадратов. Для n = 8 за три часа ни одного не нашлось, и процесс ещё не завершился.
Попробуйте что-то здесь ещё оптимизировать, у меня мысли закончились.
При отладке выяснилось, что самое прожорливое по времени условие в цикле проверки ортогональности при генерации квадрата (помечено стрелкой).
#include <stdio.h>
#include <conio.h>
#define n 10
#define mask ~((-1) << n)
#define border (1 << n)
char s[n][n] = {{"0572164938"}, {"6051298473"}, {"4867039215"},
{"1439807652"}, {"8324756091"}, {"7203941586"}, {"5610473829"},
{"9148625307"}, {"2795380164"}, {"3986512740"}};
int q[n][n], a[n][n];
int p[n * n];
long long m = 0;
void solution(int, int);
int main()
{
int i, j;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
{
q[i][j] = 1 << (s[i][j] -= '0');
a[i][j] = border;
}
solution(0, 0);
printf("Ортогональных латинских квадратов: %d%09d\n", (int)(m / 1000000000), (int)(m % 1000000000));
getch();
return 0;
}
void solution(int i, int j)
{
int k, t, r, v, set = 0;
for (k = 0; k < i || k < j; k++)
set |= a[i][k] | a[k][j];
for (k = 1; (set & mask) != mask && !(k & border); k <<= 1)
if (!(set & k))
{
v = q[i][j] << 2 * n | k;
for (t = i * n + j - 1; t >= 0; t--)
if (p[t] == v) break; // <========
if (t < 0)
{
t = i;
r = j >= n - 1? t++, r = 0 : j + 1;
if (t >= n) m++;
else
{
p[i * n + j] = v;
a[i][j] = k;
solution(t, r);
a[i][j] = border;
}
}
}
}
Для хотя бы какого-то ускорения, построение идет бинарными полями. Поэтому, если потребуется выводить полученные квадраты, придётся их предварительно декодировать.
Для порядков n = 3, 4, 5, 7 получено соответственно 6, 48, 360, 3200400 ортогональных квадратов. Для n = 8 за три часа ни одного не нашлось, и процесс ещё не завершился.
Попробуйте что-то здесь ещё оптимизировать, у меня мысли закончились.
При отладке выяснилось, что самое прожорливое по времени условие в цикле проверки ортогональности при генерации квадрата (помечено стрелкой).
#include
#include
#define n 10
#define mask ~((-1) << n)
#define border (1 << n)
char s[n][n] = {{"0572164938"}, {"6051298473"}, {"4867039215"},
{"1439807652"}, {"8324756091"}, {"7203941586"}, {"5610473829"},
{"9148625307"}, {"2795380164"}, {"3986512740"}};
int q[n][n], a[n][n];
int p[n * n];
long long m = 0;
void solution(int, int);
int main()
{
int i, j;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
{
q[i][j] = 1 << (s[i][j] -= '0');
a[i][j] = border;
}
solution(0, 0);
printf("Ортогональных латинских квадратов: %d%09d\n", (int)(m / 1000000000), (int)(m % 1000000000));
getch();
return 0;
}
void solution(int i, int j)
{
int k, t, r, v, set = 0;
for (k = 0; k < i || k < j; k++)
set |= a[i][k] | a[k][j];
for (k = 1; (set & mask) != mask && !(k & border); k <<= 1)
if (!(set & k))
{
v = q[i][j] << 2 * n | k;
for (t = i * n + j - 1; t >= 0; t--)
if (p[t] == v) break; // <========
if (t < 0)
{
t = i;
r = j >= n - 1? t++, r = 0 : j + 1;
if (t >= n) m++;
else
{
p[i * n + j] = v;
a[i][j] = k;
solution(t, r);
a[i][j] = border;
}
}
}
}
#include
#define n 10
#define mask ~((-1) << n)
#define border (1 << n)
char s[n][n] = {{"0572164938"}, {"6051298473"}, {"4867039215"},
{"1439807652"}, {"8324756091"}, {"7203941586"}, {"5610473829"},
{"9148625307"}, {"2795380164"}, {"3986512740"}};
int q[n][n], a[n][n];
int p[n * n];
long long m = 0;
void solution(int, int);
int main()
{
int i, j;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
{
q[i][j] = 1 << (s[i][j] -= '0');
a[i][j] = border;
}
solution(0, 0);
printf("Ортогональных латинских квадратов: %d%09d\n", (int)(m / 1000000000), (int)(m % 1000000000));
getch();
return 0;
}
void solution(int i, int j)
{
int k, t, r, v, set = 0;
for (k = 0; k < i || k < j; k++)
set |= a[i][k] | a[k][j];
for (k = 1; (set & mask) != mask && !(k & border); k <<= 1)
if (!(set & k))
{
v = q[i][j] << 2 * n | k;
for (t = i * n + j - 1; t >= 0; t--)
if (p[t] == v) break; // <========
if (t < 0)
{
t = i;
r = j >= n - 1? t++, r = 0 : j + 1;
if (t >= n) m++;
else
{
p[i * n + j] = v;
a[i][j] = k;
solution(t, r);
a[i][j] = border;
}
}
}
}
Похожие вопросы
- 1. как в строке выбрать все русские буквы по одному разу? 2.как заполнить массив по правилу латинского квадрата?
- помогите пожалуйста зашифровать сообщения квадратом полибия 6х6
- доброе утро программисти вопрос в нутри вопрос какой язык вибрать помогите кто чем сможеть
- Кто знает язык Си? ПОМОГИТЕ ПОЖАЛУЙСТА!!!
- Программисты, знающие язык С, помогите.
- Языки программирования:помогите
- Программисты, знающие язык С, помогите.
- Язык VBA помогите составить задачу!
- язык программирования помогите!
- Язык Си. Помогите пожалуйста написать простую программу.
void solution(int i, int j)
{
int k, t, r, set=0;
for (k = 0; k < i || k < j; k++)
set |= (1 << a[i][k]) | (1 << a[k][j]);
for (k = 0; (set & mask) != mask && k < n; k++)
if (!(set & (1 << k)) && p[q[i][j]][k] == 0)
{
t = i; r = j >= n - 1? t++, 0 : j + 1;
if (t >= n) m++;
else
{
p[q[i][j]][k]++;
a[i][j] = k;
solution(t, r);
a[i][j] = n;
p[q[i][j]][k]--;
}
}
}
то процесс ускоряется в несколько раз, но принципиально проблему не решает.