From adba0bfac625dd2fe6eb57c27a9bb79d439e5d86 Mon Sep 17 00:00:00 2001 From: nihonium Date: Fri, 8 Apr 2022 12:14:50 +0300 Subject: [PATCH] algo --- algo/first/application_select.c | 79 +++++++++++++++++++ algo/first/application_select.data | 15 ++++ algo/first/dijkstra.c | 120 +++++++++++++++++++++++++++++ algo/first/dijkstra.data | 10 +++ algo/first/prim.c | 91 ++++++++++++++++++++++ algo/first/prim.data | 6 ++ algo/first/topological.c | 78 +++++++++++++++++++ algo/first/topological.data | 7 ++ algo/first/warshall.c | 51 ++++++++++++ algo/first/warshall.data | 9 +++ 10 files changed, 466 insertions(+) create mode 100644 algo/first/application_select.c create mode 100644 algo/first/application_select.data create mode 100644 algo/first/dijkstra.c create mode 100644 algo/first/dijkstra.data create mode 100644 algo/first/prim.c create mode 100644 algo/first/prim.data create mode 100644 algo/first/topological.c create mode 100644 algo/first/topological.data create mode 100644 algo/first/warshall.c create mode 100644 algo/first/warshall.data diff --git a/algo/first/application_select.c b/algo/first/application_select.c new file mode 100644 index 0000000..8dd7ccb --- /dev/null +++ b/algo/first/application_select.c @@ -0,0 +1,79 @@ +#include +#include + +/*O(n*log(n) + n), сортировка плюс проход по массиву заявок */ + +/* Структура для хранения зявки */ +typedef struct application { + int begin; + int end; +} app; + +int vector_compare(const void *a, const void *b); +app* solve(app* vector, unsigned int* NUM); + +int main() { + /* Число заявок */ + unsigned int N; + scanf("%d", &N); + app* vector = (app*)calloc(N, sizeof(app)); + + /* Считываем информацию о заявках, начало-конец */ + for (unsigned int i = 0; i < N; i++) { + scanf("%d %d", &vector[i].begin, &vector[i].end); + } + + /* Сортируем заявки по времени окончания */ + qsort(vector, N, sizeof(app), vector_compare); + + /* Указатель на vector заменится, N изменится */ + vector = solve(vector, &N); + + 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); +} + +int vector_compare(const void *a, const void *b) { + return ((const app *)a)->end - ((const app *)b)->end; +} + +/* Учитываем, что время не может быть отрицательным, тем самым +избавляясь от надобности создавать три указателя или же +прибегать к сложной сортировке */ + +app *solve(app *vector, unsigned int *N) { + /* Сохраняем начальное значение N */ + unsigned int N_init = *N; + /* Конец очередной заявки */ + int end = vector[0].end; + for (unsigned int i = 1; i < N_init; i++) { + if (end > vector[i].begin) { + /* Удаляем заявки, время начала которых раньше времени конца */ + vector[i].begin = vector[i].end = -1; + /* Изменяем количество заявок */ + (*N)--; + } + else { + /* Иначе, обновляем значение очередного конца */ + end = vector[i].end; + } + } + + app* vector_res = (app*)calloc(*N, sizeof(app)); + 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; +} diff --git a/algo/first/application_select.data b/algo/first/application_select.data new file mode 100644 index 0000000..9d6f930 --- /dev/null +++ b/algo/first/application_select.data @@ -0,0 +1,15 @@ +# 1 + +5 +1 2 +3 6 +3 4 +5 7 +1 7 + +# 2 + +3 +1 5 +2 3 +3 4 diff --git a/algo/first/dijkstra.c b/algo/first/dijkstra.c new file mode 100644 index 0000000..81573b9 --- /dev/null +++ b/algo/first/dijkstra.c @@ -0,0 +1,120 @@ +#include +#include +#include + +/* O(n^2) */ + +int* solve(int** massiv, int n, int x); // 0 вершина(можно заменить в коде) +void route(int** massiv, int* problem, int n, int x);// для 0 вершины + +int main() { + int n; + int x; + + scanf("%d", &n); + int **adj = (int**)calloc(n, sizeof(int*)); + for (int i = 0; i < n; i++) { + adj[i] = (int*)calloc(n, sizeof(int)); + } + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + scanf("%d", &adj[i][j]); + } + } + + /* Номер вершины */ + scanf("%d", &x); + + int *res = solve(adj, n, x); + + route(adj, res, n, x); + + for (int i = 0; i < n; i++) { + free(adj[i]); + } + free(adj); + + free(res); +} + +int *solve(int **adj, int n, int x) { + /* Пройденные вершины - 1, непройденные - 0 */ + int *vertics = (int*)calloc(n, sizeof(int)); + /* Вершины, из которых быстрее всего добраться */ + int *res = (int*)calloc(n, sizeof(int)); + /* Количество пройденных вершин */ + int size = 1; + /* Массив с длинами ребер, из которых выбираем */ + int* arr = (int*)calloc(n, sizeof(int)); + /* Начальная вершина */ + int vertic = x; + /* Делаем начальную вершину выбранной */ + vertics[vertic] = 1; + for (int i = 0; i < n; i++) { + arr[i] = adj[vertic][i]; + res[i] = vertic; + } + while (size != n) { + int min = INT_MAX; + int k; + for (int i = 0; i < n; i++) { + /* Пропускаем пройденные вершины */ + if (vertics[i] == 1) { + continue; + } + /* Ищем вершину, до которой ближе всего (с номером k) */ + if (min > arr[i]) { + min = arr[i]; + k = i; + } + } + /* Отмечаем найденную вершину "пройденной" */ + vertics[k] = 1; + /* Смотрим, изменится ли наш массив рёбер, если будем "шагать" из выбранной вершины */ + for (int i = 0; i < n; i++) { + /* Игнорируем пройденные вершины */ + if (vertics[i] == 1) { + continue; + } + /* Если из вершины k ближе до вершины i, то обновляем знaчение для i */ + if (arr[i] > min + adj[k][i]) { + arr[i] = min + adj[k][i]; + res[i] = k; + } + } + + size++; + } + free(vertics); + free(arr); + return res; +} + +void route(int **adj, int *res, int n, int x) { + for (int i = 0; i < n; i++) { + /* Игнорируем петли */ + if (i == x) { + continue; + } + int w = i; + /* Суммарная длина */ + int sum = 0; + /* Если есть прямой короткий путь, то выводим его */ + if (res[i] == x) { + sum = adj[x][i]; + printf("%d: %d-%d\n", i, i, x); + } + /* Иначе, последовательно идем по вершинам из res */ + else { + printf("%d: %d-", i, i); + while (res[w] != x) { + sum += adj[res[w]][w]; + printf("%d-", res[w]); + w = res[w]; + } + sum += adj[x][w]; + printf("%d\n", x); + } + printf("Расстояние: %d\n###\n", sum); + } +} diff --git a/algo/first/dijkstra.data b/algo/first/dijkstra.data new file mode 100644 index 0000000..3208ff6 --- /dev/null +++ b/algo/first/dijkstra.data @@ -0,0 +1,10 @@ +8 +0 23 12 999 999 999 999 999 +23 0 25 999 22 999 999 35 +12 25 0 18 999 999 999 999 +999 999 18 0 999 20 999 999 +999 22 999 999 0 23 14 999 +999 999 999 20 23 0 24 999 +999 999 999 999 14 24 0 16 +999 35 999 999 999 999 16 0 +4 diff --git a/algo/first/prim.c b/algo/first/prim.c new file mode 100644 index 0000000..4ba6ae3 --- /dev/null +++ b/algo/first/prim.c @@ -0,0 +1,91 @@ +#define _CRT_SECURE_NO_WARNINGS +#include +#include +#include + +/* O(n^2), n - количество вершин, используем матрицу смежности */ + +void solve(int **adj, int **res, int n); + +int main() { + int n; + + scanf("%d", &n); + int **adj = (int**)calloc(n, sizeof(int*)); + for (int i = 0; i < n; i++) { + adj[i] = (int*)calloc(n, sizeof(int)); + } + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + scanf("%d", &adj[i][j]); + } + } + + int **res = (int**)calloc(n, sizeof(int*)); + for (int i = 0; i < n; i++) { + res[i] = (int*)calloc(n, sizeof(int)); + } + + solve(adj, res, n); + + 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]); + } + } + } + + /* Освобождаем память */ + for (int i = 0; i < n; i++) { + free(adj[i]); + } + free(adj); + for (int i = 0; i < n; i++) { + free(res[i]); + } + free(res); +} + +void solve(int **adj, int **res, int n) { + /* Множество выбранных вершин, 1 - выбрано, 0 - не выбрано */ + int* set = (int *)calloc(n, sizeof(int)); + /* Выбрали первую вершину */ + set[0] = 1; + /* Количество выбранных вершин */ + int set_size = 1; + while (set_size != n) { + /* "Бесконечность" */ + int min = INT_MAX; + /* Номер вершины */ + int k_i; + int k_j; + for (int i = 0; i < n; i++) { + /* Если вершина еще не выбрана, то пропускаем её */ + if (!set[i]) { + continue; + } + /* Рассматриваем выбранные вешины */ + for (int j = 0; j < n; j++) { + /* Если вершина k_j выбрана, то пропускаем её, она уже в компоненте связности */ + if (set[j] == 1) { + continue; + } + /* Выбираем кратчайшее ребро */ + if (min > adj[i][j] && adj[i][j]) { + min = adj[i][j]; + k_i = i; + k_j = j; + } + } + } + /* Добавляем вершину k_j в компоненту связности */ + set[k_j] = 1; + /* Сохраняем в симметрическую матрицу результат */ + res[k_i][k_j] = adj[k_i][k_j]; + res[k_j][k_i] = adj[k_i][k_j]; + set_size++; + } + free(set); +} diff --git a/algo/first/prim.data b/algo/first/prim.data new file mode 100644 index 0000000..a1155bc --- /dev/null +++ b/algo/first/prim.data @@ -0,0 +1,6 @@ +5 +0 9 75 0 0 +9 0 95 19 42 +75 95 0 51 66 +0 19 51 0 31 +0 42 66 31 0 diff --git a/algo/first/topological.c b/algo/first/topological.c new file mode 100644 index 0000000..a8af486 --- /dev/null +++ b/algo/first/topological.c @@ -0,0 +1,78 @@ +#include +#include +#include + +/* O(n) - алгоритм Тарьяна */ +int* solve(int** massiv, int n); +void dfs(int** massiv, int size, int* paint, int vertex, int* problem, int* len); + +int main(){ + int n; + + scanf("%d", &n); + int **adj = (int**)calloc(n, sizeof(int*)); + for (int i = 0; i < n; i++) { + adj[i] = (int*)calloc(n, sizeof(int)); + } + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + scanf("%d", &adj[i][j]); + } + } + + int *res = solve(adj, n); + + for (int i = 0; i < n; ++i) { + printf("%d ", res[i]); + } + + /* Освобождаем память */ + for (int i = 0; i < n; i++) { + free(adj[i]); + } + free(adj); + free(res); + +} + +int* solve(int** adj, int n) { + int* res = (int*)calloc(n, sizeof(int)); + /* Список раскрасок вершин, 0 - белый, 1 - серый, 2 - черный */ + int* paint = (int*)calloc(n, sizeof(int)); + int len = n - 1; + for (int i = 0; i < n; i++) { + if (paint[i] == 0) { + dfs(adj, n, paint, i, res, &len); + } + /* Если нашлась серая вершина на данном шаге, то граф цикличен */ + else if (paint[i] == 1) { + printf("Граф цикличен, решения не существует:\n"); + assert(0); + } + } + + free(paint); + return res; +} +void dfs(int **adj, int size, int* paint, int vertex, int* res, int* len) { + if (paint[vertex] == 0) { + /* Красим белую вершину в серую */ + paint[vertex] = 1; + /* вызываем поиск в глубину для каждой вершины, в которую можем дойти из данной, рекурсивно */ + for (int i = 0; i < size; i++) { + if (adj[vertex][i] == 1) { + dfs(adj, size, paint, i, res, len); + } + } + /* Заносим вершину в список для вывода */ + res[(*len)--] = vertex; + /* Красим вершину в черный, она обработана */ + paint[vertex] = 2; + + } + /* Если нашлась серая вершина - граф цикличен */ + else if (paint[vertex] == 1) { + printf("Граф цикличен, решения не существует:\n"); + assert(0); + } +} diff --git a/algo/first/topological.data b/algo/first/topological.data new file mode 100644 index 0000000..8272198 --- /dev/null +++ b/algo/first/topological.data @@ -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 diff --git a/algo/first/warshall.c b/algo/first/warshall.c new file mode 100644 index 0000000..bf8fee2 --- /dev/null +++ b/algo/first/warshall.c @@ -0,0 +1,51 @@ +#include +#include + +/* O(n^3) */ + +void solve(int** adj, int n); + +int main() { + int n; + scanf("%d", &n); + int **adj = (int**)calloc(n, sizeof(int*)); + for (int i = 0; i < n; i++) { + adj[i] = (int*)calloc(n, sizeof(int)); + } + /* Считываем матрицу смежности. Вместо бесконечности выступает 9999 */ + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + scanf("%d", &adj[i][j]); + } + } + + solve(adj, n); + + printf("Решение:\n"); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + printf("%d ", adj[i][j]); + } + printf("\n"); + } + + /* Освобождаем память */ + for (int i = 0; i < n; i++) { + free(adj[i]); + } + free(adj); + +} + +void solve(int **adj, int n) { + /* Перебираем все варианты добраться из i в j через k, если выходит короче, то перезаписываем значение i->j */ + for (int k = 0; k < n; k++) { + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (adj[i][k] + adj[k][j] < adj[i][j]) { + adj[i][j] = adj[i][k] + adj[k][j]; + } + } + } + } +} diff --git a/algo/first/warshall.data b/algo/first/warshall.data new file mode 100644 index 0000000..6d17523 --- /dev/null +++ b/algo/first/warshall.data @@ -0,0 +1,9 @@ +8 +0 23 12 9999 9999 9999 9999 9999 +23 0 25 9999 22 9999 9999 35 +12 25 0 18 9999 9999 9999 9999 +9999 9999 18 0 9999 20 9999 9999 +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