finished first algo
This commit is contained in:
parent
4f48405b54
commit
16d8843135
12 changed files with 252 additions and 189 deletions
|
@ -16,7 +16,10 @@ warshall_run: warshall
|
||||||
build_topological: topological.c
|
build_topological: topological.c
|
||||||
$(CC) $(CFLAGS) topological.c -o topological
|
$(CC) $(CFLAGS) topological.c -o topological
|
||||||
topological_run: topological
|
topological_run: topological
|
||||||
cat topological.data | ./topological
|
@printf '===Без циклов:===\n'
|
||||||
|
cat topological_good.data | ./topological
|
||||||
|
@printf "\n===С циклом:===\n"
|
||||||
|
cat topological_bad.data | ./topological
|
||||||
|
|
||||||
build_dijkstra: dijkstra.c
|
build_dijkstra: dijkstra.c
|
||||||
$(CC) $(CFLAGS) dijkstra.c -o dijkstra
|
$(CC) $(CFLAGS) dijkstra.c -o dijkstra
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
/*O(n*log(n) + n), сортировка плюс проход по массиву заявок */
|
/* O(n*log(n) + n), сортировка плюс проход по массиву заявок */
|
||||||
|
|
||||||
/* Структура для хранения зявки */
|
/* Структура для хранения заявки */
|
||||||
typedef struct application {
|
typedef struct application {
|
||||||
int begin;
|
int begin;
|
||||||
int end;
|
int end;
|
||||||
} app;
|
} app;
|
||||||
|
|
||||||
int vector_compare(const void *a, const void *b);
|
int vector_compare(const void *a, const void *b);
|
||||||
app* solve(app* vector, unsigned int* NUM);
|
int solve(app *vector, unsigned int N);
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
/* Число заявок */
|
/* Число заявок */
|
||||||
|
@ -26,13 +26,8 @@ int main() {
|
||||||
/* Сортируем заявки по времени окончания */
|
/* Сортируем заявки по времени окончания */
|
||||||
qsort(vector, N, sizeof(app), vector_compare);
|
qsort(vector, N, sizeof(app), vector_compare);
|
||||||
|
|
||||||
/* Указатель на vector заменится, N изменится */
|
int result = solve(vector, N);
|
||||||
vector = solve(vector, &N);
|
printf("Количество выполненных заявок:%d\n", result);
|
||||||
|
|
||||||
printf("Решение:\nКоличество выполненных заявок:%d\n", N);
|
|
||||||
for (unsigned int i = 0; i < N; i++) {
|
|
||||||
printf("%i %i\n", vector[i].begin, vector[i].end);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(vector);
|
free(vector);
|
||||||
}
|
}
|
||||||
|
@ -41,21 +36,16 @@ int vector_compare(const void *a, const void *b) {
|
||||||
return ((const app *)a)->end - ((const app *)b)->end;
|
return ((const app *)a)->end - ((const app *)b)->end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Учитываем, что время не может быть отрицательным, тем самым
|
int solve(app *vector, unsigned int N) {
|
||||||
избавляясь от надобности создавать три указателя или же
|
|
||||||
прибегать к сложной сортировке */
|
|
||||||
|
|
||||||
app *solve(app *vector, unsigned int *N) {
|
|
||||||
/* Сохраняем начальное значение N */
|
/* Сохраняем начальное значение N */
|
||||||
unsigned int N_init = *N;
|
unsigned int result = N;
|
||||||
/* Конец очередной заявки */
|
/* Конец очередной заявки */
|
||||||
int end = vector[0].end;
|
int end = vector[0].end;
|
||||||
for (unsigned int i = 1; i < N_init; i++) {
|
for (unsigned int i = 1; i < N; i++) {
|
||||||
if (end > vector[i].begin) {
|
if (end > vector[i].begin) {
|
||||||
/* Удаляем заявки, время начала которых раньше времени конца */
|
/* Удаляем заявки, время начала которых раньше времени конца
|
||||||
vector[i].begin = vector[i].end = -1;
|
Изменяем счетчик заявок */
|
||||||
/* Изменяем количество заявок */
|
(result)--;
|
||||||
(*N)--;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Иначе, обновляем значение очередного конца */
|
/* Иначе, обновляем значение очередного конца */
|
||||||
|
@ -63,17 +53,5 @@ app *solve(app *vector, unsigned int *N) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app* vector_res = (app*)calloc(*N, sizeof(app));
|
return result;
|
||||||
unsigned int j = 0;
|
|
||||||
/* Два случая: нужные заявки в конце, нужные заявки в начале */
|
|
||||||
for (unsigned int i = 0; i < N_init && j != *N; i++) {
|
|
||||||
/* Если заявка не помечена недействительной, то вписываем ее в новый массив */
|
|
||||||
if (vector[i].begin != -1) {
|
|
||||||
vector_res[j] = vector[i];
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(vector);
|
|
||||||
return vector_res;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,31 +4,51 @@
|
||||||
|
|
||||||
/* O(n^2) */
|
/* O(n^2) */
|
||||||
|
|
||||||
int* solve(int** massiv, int n, int x); // 0 вершина(можно заменить в коде)
|
typedef struct vertex_s {
|
||||||
void route(int** massiv, int* problem, int n, int x);// для 0 вершины
|
int val;
|
||||||
|
/* 0 - непройденная, 1 - пройденная */
|
||||||
|
int sel;
|
||||||
|
} vertex;
|
||||||
|
|
||||||
|
vertex *solve(unsigned int **adj, int n, int x); // 0 вершина(можно заменить в коде)
|
||||||
|
void route(int **adj, vertex *res, int n, int x);// для 0 вершины
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
/* Количество вершин и номер нужной для отсчета вершины */
|
||||||
int n;
|
int n;
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
scanf("%d", &n);
|
scanf("%d", &n);
|
||||||
int **adj = (int**)calloc(n, sizeof(int*));
|
unsigned int **adj = (unsigned int**)calloc(n, sizeof(unsigned int *));
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
adj[i] = (int*)calloc(n, sizeof(int));
|
adj[i] = (unsigned int*)calloc(n, sizeof(unsigned int));
|
||||||
}
|
}
|
||||||
|
/* В нашей матрице смежности 0 обозначает отсутствие пути из одной вершины в другую */
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
for (int j = 0; j < n; j++) {
|
for (int j = 0; j < n; j++) {
|
||||||
scanf("%d", &adj[i][j]);
|
scanf("%d", &adj[i][j]);
|
||||||
|
if (!adj[i][j])
|
||||||
|
adj[i][j] = INT_MAX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Номер вершины */
|
#ifdef _DEBUG
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
for (int j = 0; j < n; j++) {
|
||||||
|
printf("%d\t", adj[i][j]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
scanf("%d", &x);
|
scanf("%d", &x);
|
||||||
|
|
||||||
int *res = solve(adj, n, x);
|
vertex *res = solve(adj, n, x);
|
||||||
|
|
||||||
|
/* Вывод результата, расстояние от каждой вершины до данной с путем */
|
||||||
route(adj, res, n, x);
|
route(adj, res, n, x);
|
||||||
|
|
||||||
|
/* Освобождаем память */
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
free(adj[i]);
|
free(adj[i]);
|
||||||
}
|
}
|
||||||
|
@ -37,60 +57,67 @@ int main() {
|
||||||
free(res);
|
free(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
int *solve(int **adj, int n, int x) {
|
vertex *solve(unsigned int **adj, int n, int x) {
|
||||||
/* Пройденные вершины - 1, непройденные - 0 */
|
vertex *res = (vertex *)calloc(n, sizeof(vertex));
|
||||||
int *vertics = (int*)calloc(n, sizeof(int));
|
|
||||||
/* Вершины, из которых быстрее всего добраться */
|
|
||||||
int *res = (int*)calloc(n, sizeof(int));
|
|
||||||
/* Количество пройденных вершин */
|
/* Количество пройденных вершин */
|
||||||
int size = 1;
|
int size = 1;
|
||||||
/* Массив с длинами ребер, из которых выбираем */
|
|
||||||
int* arr = (int*)calloc(n, sizeof(int));
|
/* Массив с длинами ребер, из которых выбираем для каждой вершины */
|
||||||
|
unsigned int *distance = (unsigned int*)calloc(n, sizeof(unsigned int));
|
||||||
|
|
||||||
/* Начальная вершина */
|
/* Начальная вершина */
|
||||||
int vertic = x;
|
int v = x;
|
||||||
|
|
||||||
/* Делаем начальную вершину выбранной */
|
/* Делаем начальную вершину выбранной */
|
||||||
vertics[vertic] = 1;
|
res[v].sel = 1;
|
||||||
|
|
||||||
|
/* Смотрим, как выбранная вершина соотносится с другими, заполняем массив расстояний */
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
arr[i] = adj[vertic][i];
|
distance[i] = adj[v][i];
|
||||||
res[i] = vertic;
|
res[i].val = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Пока не переберем все вершины */
|
||||||
while (size != n) {
|
while (size != n) {
|
||||||
int min = INT_MAX;
|
/* Минимальное расстояние до вершины, изначально - бесконечность */
|
||||||
|
unsigned int min = INT_MAX;
|
||||||
|
/* Номер очередной вершины */
|
||||||
int k;
|
int k;
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
/* Пропускаем пройденные вершины */
|
/* Пропускаем пройденные вершины */
|
||||||
if (vertics[i] == 1) {
|
if (res[i].sel == 1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Ищем вершину, до которой ближе всего (с номером k) */
|
/* Ищем вершину, до которой ближе всего (с номером k) */
|
||||||
if (min > arr[i]) {
|
if (min >= distance[i]) {
|
||||||
min = arr[i];
|
min = distance[i];
|
||||||
k = i;
|
k = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Отмечаем найденную вершину "пройденной" */
|
/* Отмечаем найденную вершину "пройденной" */
|
||||||
vertics[k] = 1;
|
res[k].sel = 1;
|
||||||
/* Смотрим, изменится ли наш массив рёбер, если будем "шагать" из выбранной вершины */
|
/* Смотрим, изменится ли наш массив рёбер, если будем "шагать" из выбранной вершины */
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
/* Игнорируем пройденные вершины */
|
/* Игнорируем пройденные вершины */
|
||||||
if (vertics[i] == 1) {
|
if (res[i].sel == 1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Если из вершины k ближе до вершины i, то обновляем знaчение для i */
|
/* Если из вершины k ближе до вершины i, то обновляем знaчение для i */
|
||||||
if (arr[i] > min + adj[k][i]) {
|
if (distance[i] > min + adj[k][i]) {
|
||||||
arr[i] = min + adj[k][i];
|
distance[i] = min + adj[k][i];
|
||||||
res[i] = k;
|
res[i].val = k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size++;
|
size++;
|
||||||
}
|
}
|
||||||
free(vertics);
|
|
||||||
free(arr);
|
free(distance);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void route(int **adj, int *res, int n, int x) {
|
void route(int **adj, vertex *res, int n, int x) {
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
/* Игнорируем петли */
|
/* Игнорируем петли */
|
||||||
if (i == x) {
|
if (i == x) {
|
||||||
|
@ -100,17 +127,17 @@ void route(int **adj, int *res, int n, int x) {
|
||||||
/* Суммарная длина */
|
/* Суммарная длина */
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
/* Если есть прямой короткий путь, то выводим его */
|
/* Если есть прямой короткий путь, то выводим его */
|
||||||
if (res[i] == x) {
|
if (res[i].val == x) {
|
||||||
sum = adj[x][i];
|
sum = adj[x][i];
|
||||||
printf("%d: %d-%d\n", i, i, x);
|
printf("%d: %d-%d\n", i, i, x);
|
||||||
}
|
}
|
||||||
/* Иначе, последовательно идем по вершинам из res */
|
/* Иначе, последовательно идем по вершинам из res */
|
||||||
else {
|
else {
|
||||||
printf("%d: %d-", i, i);
|
printf("%d: %d-", i, i);
|
||||||
while (res[w] != x) {
|
while (res[w].val != x) {
|
||||||
sum += adj[res[w]][w];
|
sum += adj[res[w].val][w];
|
||||||
printf("%d-", res[w]);
|
printf("%d-", res[w].val);
|
||||||
w = res[w];
|
w = res[w].val;
|
||||||
}
|
}
|
||||||
sum += adj[x][w];
|
sum += adj[x][w];
|
||||||
printf("%d\n", x);
|
printf("%d\n", x);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
8
|
8
|
||||||
0 23 12 999 999 999 999 999
|
0 23 12 0 0 0 0 0
|
||||||
23 0 25 999 22 999 999 35
|
23 0 25 0 22 0 0 35
|
||||||
12 25 0 18 999 999 999 999
|
12 25 0 18 0 0 0 0
|
||||||
999 999 18 0 999 20 999 999
|
0 0 18 0 0 20 0 0
|
||||||
999 22 999 999 0 23 14 999
|
0 22 0 0 0 23 14 0
|
||||||
999 999 999 20 23 0 24 999
|
0 0 0 20 23 0 24 0
|
||||||
999 999 999 999 14 24 0 16
|
0 0 0 0 14 24 0 16
|
||||||
999 35 999 999 999 999 16 0
|
0 35 0 0 0 0 16 0
|
||||||
4
|
4
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* Ребра */
|
||||||
typedef struct edge {
|
typedef struct edge {
|
||||||
int begin;
|
int begin;
|
||||||
int end;
|
int end;
|
||||||
|
@ -30,11 +31,13 @@ int main() {
|
||||||
}
|
}
|
||||||
/* Подсчет количества ребер в исходной матрице смежности */
|
/* Подсчет количества ребер в исходной матрице смежности */
|
||||||
int size = count_edge(adj, n);
|
int size = count_edge(adj, n);
|
||||||
|
/* Создаем массив с ребрами */
|
||||||
Edge *vector = create_edge_vector(adj, n, size);
|
Edge *vector = create_edge_vector(adj, n, size);
|
||||||
/* Сортируем ребра по длине, сначала самые короткие */
|
/* Сортируем ребра по длине, сначала самые короткие */
|
||||||
qsort(vector, size, sizeof(Edge), vector_compare);
|
qsort(vector, size, sizeof(Edge), vector_compare);
|
||||||
|
|
||||||
int **res = solve(vector, size, n);
|
int **res = solve(vector, size, n);
|
||||||
|
/* Вывод списка имеющихся ребер по матрице смежности */
|
||||||
print_edges(res, n);
|
print_edges(res, n);
|
||||||
|
|
||||||
/* Освобождаем память */
|
/* Освобождаем память */
|
||||||
|
@ -50,29 +53,34 @@ int main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int **solve(Edge* vector, int size, int v) {
|
int **solve(Edge* vector, int size, int v) {
|
||||||
|
/* size - ребра, v - вершины */
|
||||||
/* Результирующее остовное дерево в виде матрицы смежности */
|
/* Результирующее остовное дерево в виде матрицы смежности */
|
||||||
int** res = (int**)calloc(v, sizeof(int*));
|
int** res = (int**)calloc(v, sizeof(int*));
|
||||||
for (int i = 0; i < v; i++) {
|
for (int i = 0; i < v; i++) {
|
||||||
res[i] = (int*)calloc(v, sizeof(int));
|
res[i] = (int*)calloc(v, sizeof(int));
|
||||||
}
|
}
|
||||||
/* Массив с окраской каждой вершины */
|
/* Массив с окраской каждой вершины */
|
||||||
int* paint = (int*)calloc(v, sizeof(int));
|
int *paint = (int*)calloc(v, sizeof(int));
|
||||||
/* Количество рассмотренных вершин */
|
/* Количество рассмотренных вершин */
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
/* Текущий цвет */
|
||||||
int color = 1;
|
int color = 1;
|
||||||
|
/* Сохраненный цвет для перекрашивания (объединение двух компонент) */
|
||||||
int saved_color;
|
int saved_color;
|
||||||
/* Пока не раскрашены все вершины */
|
/* Пока не раскрашены все вершины */
|
||||||
while (n != size ) {
|
while (n != size ) {
|
||||||
/* Проверяем на цикл */
|
/* Проверяем, соединяет ли очередное ребро вершины из уже имеющейся компоненты одного цвета (цвет 0 - отсутствие цвета) */
|
||||||
if ((paint[vector[n].begin] == paint[vector[n].end]) && (paint[vector[n].begin] != 0 || paint[vector[n].end] != 0)) {
|
if ((paint[vector[n].begin] == paint[vector[n].end]) && (paint[vector[n].begin] != 0 || paint[vector[n].end] != 0)) {
|
||||||
n++;
|
n++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Создание новой компоненты связности */
|
/* Создание новой компоненты связности и добавление результата в результирующую матрицу смежности */
|
||||||
if (paint[vector[n].begin] == 0 && paint[vector[n].end] == 0) {//обе вершины незакрашены
|
/* Обе вершины бесцветные */
|
||||||
|
if (paint[vector[n].begin] == 0 && paint[vector[n].end] == 0) {
|
||||||
paint[vector[n].begin] = color;
|
paint[vector[n].begin] = color;
|
||||||
paint[vector[n].end] = color;
|
paint[vector[n].end] = color;
|
||||||
|
|
||||||
res[vector[n].begin][vector[n].end] = vector[n].len;
|
res[vector[n].begin][vector[n].end] = vector[n].len;
|
||||||
/* Создаем новый цвет */
|
/* Создаем новый цвет */
|
||||||
color++;
|
color++;
|
||||||
|
@ -80,10 +88,12 @@ int **solve(Edge* vector, int size, int v) {
|
||||||
/* Присоединение неокрашенной вершины к существующей компоненте связности */
|
/* Присоединение неокрашенной вершины к существующей компоненте связности */
|
||||||
else if (paint[vector[n].begin] == 0) {
|
else if (paint[vector[n].begin] == 0) {
|
||||||
paint[vector[n].begin] = paint[vector[n].end];
|
paint[vector[n].begin] = paint[vector[n].end];
|
||||||
|
|
||||||
res[vector[n].begin][vector[n].end] = vector[n].len;
|
res[vector[n].begin][vector[n].end] = vector[n].len;
|
||||||
}
|
}
|
||||||
else if (paint[vector[n].end] == 0) {
|
else if (paint[vector[n].end] == 0) {
|
||||||
paint[vector[n].end] = paint[vector[n].begin];
|
paint[vector[n].end] = paint[vector[n].begin];
|
||||||
|
|
||||||
res[vector[n].begin][vector[n].end] = vector[n].len;
|
res[vector[n].begin][vector[n].end] = vector[n].len;
|
||||||
}
|
}
|
||||||
/* Объединение компонент связности */
|
/* Объединение компонент связности */
|
||||||
|
@ -91,7 +101,9 @@ int **solve(Edge* vector, int size, int v) {
|
||||||
/* Сохраняем цвет той компоненты, которую будем перекрашивать */
|
/* Сохраняем цвет той компоненты, которую будем перекрашивать */
|
||||||
saved_color = paint[vector[n].end];
|
saved_color = paint[vector[n].end];
|
||||||
paint[vector[n].end] = paint[vector[n].begin];
|
paint[vector[n].end] = paint[vector[n].begin];
|
||||||
|
|
||||||
res[vector[n].begin][vector[n].end] = vector[n].len;
|
res[vector[n].begin][vector[n].end] = vector[n].len;
|
||||||
|
|
||||||
/* Перекрашиваем вторую компоненту в цвет первой */
|
/* Перекрашиваем вторую компоненту в цвет первой */
|
||||||
paint_vertices(vector, size, vector[n].end, saved_color, paint);
|
paint_vertices(vector, size, vector[n].end, saved_color, paint);
|
||||||
}
|
}
|
||||||
|
@ -101,12 +113,11 @@ int **solve(Edge* vector, int size, int v) {
|
||||||
free(paint);
|
free(paint);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
void print_edges(int** massiv, int n) {
|
void print_edges(int **adj, int n) {
|
||||||
printf("Решение:\n");
|
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
for (int j = i + 1; j < n; j++) {
|
for (int j = i + 1; j < n; j++) {
|
||||||
if (massiv[i][j] != 0) {
|
if (adj[i][j] != 0) {
|
||||||
printf("%d-%d: %d\n", i, j, massiv[i][j]);
|
printf("%d-%d: %d\n", i, j, adj[i][j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,7 +157,7 @@ int vector_compare(const void *a, const void *b) {
|
||||||
|
|
||||||
void paint_vertices(Edge* vector, int size, int need_vertix, int saved_color, int *paint) {
|
void paint_vertices(Edge* vector, int size, int need_vertix, int saved_color, int *paint) {
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
/* Если текущая ребро выходит из нужной вершины */
|
/* Если текущее ребро выходит из нужной вершины */
|
||||||
if (vector[i].begin == need_vertix) {
|
if (vector[i].begin == need_vertix) {
|
||||||
/* Если другой конец ребра - нужный по цвету (старый), то красим в цвет исходной вершины */
|
/* Если другой конец ребра - нужный по цвету (старый), то красим в цвет исходной вершины */
|
||||||
if (paint[vector[i].end] == saved_color) {
|
if (paint[vector[i].end] == saved_color) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ typedef struct bhnode_s {
|
||||||
int priority;
|
int priority;
|
||||||
/* Значение */
|
/* Значение */
|
||||||
Data val;
|
Data val;
|
||||||
|
Data to;
|
||||||
|
|
||||||
} bhnode;
|
} bhnode;
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ binary_heap *binary_heap_new(int maxsize) {
|
||||||
void print_heap(binary_heap *bh) {
|
void print_heap(binary_heap *bh) {
|
||||||
printf("Numnodes: %d\n", bh->numnodes);
|
printf("Numnodes: %d\n", bh->numnodes);
|
||||||
for (int i = 1; i < bh->numnodes + 1; ++i) {
|
for (int i = 1; i < bh->numnodes + 1; ++i) {
|
||||||
printf("%d (priority: %d)\n", bh->body[i].val, bh->body[i].priority);
|
printf("%d to %d (priority: %d)\n", bh->body[i].val, bh->body[i].to, bh->body[i].priority);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void binary_heap_destroy(binary_heap *bh) {
|
void binary_heap_destroy(binary_heap *bh) {
|
||||||
|
@ -60,7 +61,7 @@ int binary_heap_insert(binary_heap *bh, bhnode node) {
|
||||||
}
|
}
|
||||||
bh->body[++bh->numnodes] = node;
|
bh->body[++bh->numnodes] = node;
|
||||||
for (size_t i = bh->numnodes;
|
for (size_t i = bh->numnodes;
|
||||||
i> 1 && bh->body[i].priority > bh->body[i/2].priority;
|
i> 1 && bh->body[i].priority < bh->body[i/2].priority;
|
||||||
i /= 2) {
|
i /= 2) {
|
||||||
binary_heap_swap(bh, i, i/2);
|
binary_heap_swap(bh, i, i/2);
|
||||||
}
|
}
|
||||||
|
@ -78,9 +79,9 @@ void binary_heap_erase(binary_heap *bh) {
|
||||||
size_t left = 2 * index;
|
size_t left = 2 * index;
|
||||||
size_t right = left + 1;
|
size_t right = left + 1;
|
||||||
size_t largest = index;
|
size_t largest = index;
|
||||||
if (left <= bh->numnodes && bh->body[left].priority > bh->body[index].priority)
|
if ((int) left <= bh->numnodes && bh->body[left].priority < bh->body[index].priority)
|
||||||
largest = left;
|
largest = left;
|
||||||
if (right <= bh->numnodes && bh->body[right].priority > bh->body[largest].priority)
|
if ((int) right <= bh->numnodes && bh->body[right].priority < bh->body[largest].priority)
|
||||||
largest = right;
|
largest = right;
|
||||||
if (largest == index) break;
|
if (largest == index) break;
|
||||||
binary_heap_swap(bh, index, largest);
|
binary_heap_swap(bh, index, largest);
|
||||||
|
@ -92,4 +93,23 @@ void binary_heap_erase(binary_heap *bh) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void binary_heap_recreate(binary_heap *bh) {
|
||||||
|
size_t index = 1;
|
||||||
|
for (;;) {
|
||||||
|
size_t left = 2 * index;
|
||||||
|
size_t right = left + 1;
|
||||||
|
size_t largest = index;
|
||||||
|
if ((int) left <= bh->numnodes && bh->body[left].priority < bh->body[index].priority)
|
||||||
|
largest = left;
|
||||||
|
if ((int) right <= bh->numnodes && bh->body[right].priority < bh->body[largest].priority)
|
||||||
|
largest = right;
|
||||||
|
if (largest == index) break;
|
||||||
|
binary_heap_swap(bh, index, largest);
|
||||||
|
index = largest;
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("###\n");
|
||||||
|
print_heap(bh);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include "pqueue.c"
|
||||||
|
|
||||||
/* O(n^2), n - количество вершин, используем матрицу смежности */
|
/* O(E*logV), E - количество вершин, V - число ребер, используем матрицу смежности и приоритетную очередь */
|
||||||
|
|
||||||
void solve(int **adj, int **res, int n);
|
bhnode *solve(int **adj, int n);
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
int n;
|
int n;
|
||||||
|
@ -18,23 +19,15 @@ int main() {
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
for (int j = 0; j < n; j++) {
|
for (int j = 0; j < n; j++) {
|
||||||
scanf("%d", &adj[i][j]);
|
scanf("%d", &adj[i][j]);
|
||||||
|
if (!adj[i][j])
|
||||||
|
adj[i][j] = INT_MAX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int **res = (int**)calloc(n, sizeof(int*));
|
bhnode *res = solve(adj, n);
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
res[i] = (int*)calloc(n, sizeof(int));
|
|
||||||
}
|
|
||||||
|
|
||||||
solve(adj, res, n);
|
for (int i = 1; i < n; i++) {
|
||||||
|
printf("%d-%d: %d\n", res[i].val, res[i].to, res[i].priority);
|
||||||
printf("Решение:\n");
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
for (int j = i + 1; j < n; j++) {
|
|
||||||
if (res[i][j] != 0) {
|
|
||||||
printf("%i-%i: %i\n", i, j, res[i][j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Освобождаем память */
|
/* Освобождаем память */
|
||||||
|
@ -42,50 +35,50 @@ int main() {
|
||||||
free(adj[i]);
|
free(adj[i]);
|
||||||
}
|
}
|
||||||
free(adj);
|
free(adj);
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
free(res[i]);
|
|
||||||
}
|
|
||||||
free(res);
|
free(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
void solve(int **adj, int **res, int n) {
|
bhnode *solve(int **adj, int n) {
|
||||||
/* Множество выбранных вершин, 1 - выбрано, 0 - не выбрано */
|
/* Приоритетная очередь */
|
||||||
int* set = (int *)calloc(n, sizeof(int));
|
binary_heap *bh = binary_heap_new(n);
|
||||||
/* Выбрали первую вершину */
|
|
||||||
set[0] = 1;
|
int i;
|
||||||
|
|
||||||
|
/* Результирующий массив */
|
||||||
|
bhnode *res = (bhnode *)calloc(n, sizeof(bhnode));
|
||||||
|
|
||||||
|
/* Начинаем с нулевой вершины */
|
||||||
|
|
||||||
/* Количество выбранных вершин */
|
/* Количество выбранных вершин */
|
||||||
int set_size = 1;
|
int size = 1;
|
||||||
while (set_size != n) {
|
|
||||||
/* "Бесконечность" */
|
/* Добавляем в очередь все вершины, кроме нулевой, с которой начали */
|
||||||
int min = INT_MAX;
|
for (i = 1; i < n; ++i) {
|
||||||
/* Номер вершины */
|
binary_heap_insert(bh, (bhnode) {adj[0][i], i, 0});
|
||||||
int k_i;
|
}
|
||||||
int k_j;
|
|
||||||
for (int i = 0; i < n; i++) {
|
/* Пока очередь вершин не пуста */
|
||||||
/* Если вершина еще не выбрана, то пропускаем её */
|
while (bh->numnodes) {
|
||||||
if (!set[i]) {
|
bhnode current = binary_heap_fetch(bh);
|
||||||
continue;
|
binary_heap_erase(bh);
|
||||||
}
|
#ifdef _DEBUG
|
||||||
/* Рассматриваем выбранные вешины */
|
printf("Extracted #%d to %d (%d)#\n", current.val, current.to, current.priority);
|
||||||
for (int j = 0; j < n; j++) {
|
#endif
|
||||||
/* Если вершина k_j выбрана, то пропускаем её, она уже в компоненте связности */
|
res[size++] = current;
|
||||||
if (set[j] == 1) {
|
|
||||||
continue;
|
/* Обновляем приоритеты в очереди */
|
||||||
}
|
for (i = 1; i <= bh->numnodes; ++i) {
|
||||||
/* Выбираем кратчайшее ребро */
|
if (adj[bh->body[i].val][current.val] < bh->body[i].priority) {
|
||||||
if (min > adj[i][j] && adj[i][j]) {
|
#ifdef _DEBUG
|
||||||
min = adj[i][j];
|
printf("Updated priority on %d (prev - to %d (%d)) to %d (%d)\n", bh->body[i].val, bh->body[i].to, bh->body[i].priority, current.val, adj[bh->body[i].val][current.val]);
|
||||||
k_i = i;
|
#endif
|
||||||
k_j = j;
|
bh->body[i].to = current.val;
|
||||||
}
|
bh->body[i].priority = adj[bh->body[i].val][current.val];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Добавляем вершину k_j в компоненту связности */
|
/* Сортируем заново, с новыми приоритетами */
|
||||||
set[k_j] = 1;
|
binary_heap_recreate(bh);
|
||||||
/* Сохраняем в симметрическую матрицу результат */
|
|
||||||
res[k_i][k_j] = adj[k_i][k_j];
|
|
||||||
res[k_j][k_i] = adj[k_i][k_j];
|
|
||||||
set_size++;
|
|
||||||
}
|
}
|
||||||
free(set);
|
binary_heap_destroy(bh);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,25 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
/* O(n) - алгоритм Тарьяна */
|
/* O(n) - алгоритм Тарьяна */
|
||||||
int* solve(int** massiv, int n);
|
|
||||||
void dfs(int** massiv, int size, int* paint, int vertex, int* problem, int* len);
|
typedef struct vertex_s {
|
||||||
|
int val;
|
||||||
|
/* 0 - белый, 1 - серый, 2 - черный */
|
||||||
|
int color;
|
||||||
|
} vertex;
|
||||||
|
|
||||||
|
vertex *solve(int **adj, int n);
|
||||||
|
void dfs(int **adj, int size, int v, vertex *res, int *len);
|
||||||
|
|
||||||
int main(){
|
int main(){
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
|
/* Считываем матрицу смежности */
|
||||||
scanf("%d", &n);
|
scanf("%d", &n);
|
||||||
int **adj = (int**)calloc(n, sizeof(int*));
|
int **adj = (int **)calloc(n, sizeof(int *));
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
adj[i] = (int*)calloc(n, sizeof(int));
|
adj[i] = (int *)calloc(n, sizeof(int));
|
||||||
}
|
}
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
for (int j = 0; j < n; j++) {
|
for (int j = 0; j < n; j++) {
|
||||||
|
@ -20,10 +27,11 @@ int main(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int *res = solve(adj, n);
|
vertex *res = solve(adj, n);
|
||||||
|
|
||||||
|
/* Выводим только номера вершин */
|
||||||
for (int i = 0; i < n; ++i) {
|
for (int i = 0; i < n; ++i) {
|
||||||
printf("%d ", res[i]);
|
printf("%d ", res[i].val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Освобождаем память */
|
/* Освобождаем память */
|
||||||
|
@ -35,44 +43,50 @@ int main(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int* solve(int** adj, int n) {
|
vertex *solve(int **adj, int n) {
|
||||||
int* res = (int*)calloc(n, sizeof(int));
|
vertex *res = (vertex *)calloc(n, sizeof(vertex));
|
||||||
/* Список раскрасок вершин, 0 - белый, 1 - серый, 2 - черный */
|
|
||||||
int* paint = (int*)calloc(n, sizeof(int));
|
/* len можно использовать в качестве индекса, начинающегося с нуля (в отличие от n) */
|
||||||
int len = n - 1;
|
int len = n - 1;
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
if (paint[i] == 0) {
|
/* Запускаем обход в глубину, если вершина - белая, i - номер текущей вершины */
|
||||||
dfs(adj, n, paint, i, res, &len);
|
if (res[i].color == 0) {
|
||||||
|
dfs(adj, n, i, res, &len);
|
||||||
}
|
}
|
||||||
/* Если нашлась серая вершина на данном шаге, то граф цикличен */
|
/* Если нашлась серая вершина на данном шаге, то граф цикличен */
|
||||||
else if (paint[i] == 1) {
|
else if (res[i].color == 1) {
|
||||||
printf("Граф цикличен, решения не существует:\n");
|
printf("Граф цикличен, решения не существует:\n");
|
||||||
assert(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(paint);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
void dfs(int **adj, int size, int* paint, int vertex, int* res, int* len) {
|
void dfs(int **adj, int size, int v, vertex* res, int* len) {
|
||||||
if (paint[vertex] == 0) {
|
#ifdef _DEBUG
|
||||||
|
printf("Current vertex is %d with color %d\n", v, res[v].color);
|
||||||
|
#endif
|
||||||
|
if (res[v].color == 0) {
|
||||||
/* Красим белую вершину в серую */
|
/* Красим белую вершину в серую */
|
||||||
paint[vertex] = 1;
|
res[v].color = 1;
|
||||||
/* вызываем поиск в глубину для каждой вершины, в которую можем дойти из данной, рекурсивно */
|
/* вызываем поиск в глубину для каждой вершины, в которую можем дойти из данной, рекурсивно */
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
if (adj[vertex][i] == 1) {
|
if (adj[v][i] == 1) {
|
||||||
dfs(adj, size, paint, i, res, len);
|
dfs(adj, size, i, res, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Заносим вершину в список для вывода */
|
/* Заносим вершину в список для вывода */
|
||||||
res[(*len)--] = vertex;
|
res[(*len)--].val = v;
|
||||||
|
#ifdef _DEBUG
|
||||||
|
printf("Added vertex %d\n", v);
|
||||||
|
#endif
|
||||||
/* Красим вершину в черный, она обработана */
|
/* Красим вершину в черный, она обработана */
|
||||||
paint[vertex] = 2;
|
res[v].color = 2;
|
||||||
|
|
||||||
}
|
}
|
||||||
/* Если нашлась серая вершина - граф цикличен */
|
/* Если нашлась серая вершина - граф цикличен */
|
||||||
else if (paint[vertex] == 1) {
|
else if (res[v].color == 1) {
|
||||||
printf("Граф цикличен, решения не существует:\n");
|
printf("Граф цикличен, решения не существует:\n");
|
||||||
assert(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
7
algo/first/topological_bad.data
Normal file
7
algo/first/topological_bad.data
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
6
|
||||||
|
0 1 0 0 0 1
|
||||||
|
1 0 0 0 0 0
|
||||||
|
0 0 0 0 0 0
|
||||||
|
1 0 1 0 0 0
|
||||||
|
0 0 1 0 0 0
|
||||||
|
0 0 0 0 0 0
|
7
algo/first/topological_good.data
Normal file
7
algo/first/topological_good.data
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
6
|
||||||
|
0 0 0 0 0 1
|
||||||
|
1 0 0 0 0 0
|
||||||
|
0 0 0 0 0 0
|
||||||
|
1 0 1 0 0 0
|
||||||
|
0 0 1 0 0 0
|
||||||
|
0 0 0 0 0 0
|
|
@ -3,16 +3,19 @@
|
||||||
|
|
||||||
/* O(n^3) */
|
/* O(n^3) */
|
||||||
|
|
||||||
void solve(int** adj, int n);
|
void solve(int **adj, int n);
|
||||||
|
/* Поэлементный ИЛИ над двумя строками, заменяет строку a */
|
||||||
|
void vector_or(int **adj, int n, int a, int b);
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
int n;
|
int n;
|
||||||
scanf("%d", &n);
|
scanf("%d", &n);
|
||||||
int **adj = (int**)calloc(n, sizeof(int*));
|
int **adj = (int **)calloc(n, sizeof(int*));
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
adj[i] = (int*)calloc(n, sizeof(int));
|
adj[i] = (int*)calloc(n, sizeof(int));
|
||||||
}
|
}
|
||||||
/* Считываем матрицу смежности. Вместо бесконечности выступает 9999 */
|
|
||||||
|
/* Считываем матрицу смежности */
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
for (int j = 0; j < n; j++) {
|
for (int j = 0; j < n; j++) {
|
||||||
scanf("%d", &adj[i][j]);
|
scanf("%d", &adj[i][j]);
|
||||||
|
@ -21,7 +24,6 @@ int main() {
|
||||||
|
|
||||||
solve(adj, n);
|
solve(adj, n);
|
||||||
|
|
||||||
printf("Решение:\n");
|
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
for (int j = 0; j < n; j++) {
|
for (int j = 0; j < n; j++) {
|
||||||
printf("%d ", adj[i][j]);
|
printf("%d ", adj[i][j]);
|
||||||
|
@ -38,14 +40,19 @@ int main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void solve(int **adj, int n) {
|
void solve(int **adj, int n) {
|
||||||
/* Перебираем все варианты добраться из i в j через k, если выходит короче, то перезаписываем значение i->j */
|
int i, j;
|
||||||
for (int k = 0; k < n; k++) {
|
/* Идем по матрице, рассматриваем только ненулевые элементы и не на главной диагонали */
|
||||||
for (int i = 0; i < n; i++) {
|
for (i = 0; i < n; ++i) {
|
||||||
for (int j = 0; j < n; j++) {
|
for (j = 0; j < n; ++j) {
|
||||||
if (adj[i][k] + adj[k][j] < adj[i][j]) {
|
if (adj[i][j] && (i != j)) {
|
||||||
adj[i][j] = adj[i][k] + adj[k][j];
|
/* Поэлементно "ИЛИм" строки i и j, перезаписывая строку i */
|
||||||
}
|
vector_or(adj, n, i, j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vector_or(int **adj, int n, int a, int b) {
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
adj[a][i] = adj[a][i] | adj[b][i];
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
8
|
4
|
||||||
0 23 12 9999 9999 9999 9999 9999
|
1 1 0 1
|
||||||
23 0 25 9999 22 9999 9999 35
|
1 1 0 0
|
||||||
12 25 0 18 9999 9999 9999 9999
|
1 0 1 0
|
||||||
9999 9999 18 0 9999 20 9999 9999
|
1 0 0 0
|
||||||
9999 22 9999 9999 0 23 14 9999
|
|
||||||
9999 9999 9999 20 23 0 24 9999
|
|
||||||
9999 9999 9999 9999 14 24 0 16
|
|
||||||
9999 35 9999 9999 9999 9999 16 0
|
|
||||||
|
|
Reference in a new issue