Advertisement
dmkozyrev

max_matching

Jan 22nd, 2016
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.28 KB | None | 0 0
  1. #include <stdio.h>
  2.  
  3. // Чтение графа происходит из файла in.txt, который устроен следующим образом
  4. // Сначала идет целое число n - количество вершин
  5. // Затем идет n строк по n целых чисел в каждой строке - матрица смежности графа
  6. // Запись осуществляется в файл out.txt
  7. // Выводит ребра в паросочетании
  8.  
  9. unsigned const int MAX_SIZE = 100;
  10.  
  11. void read_graph(int * graph, int * n, const char * filename);
  12. int search_path(int * graph, int n, int a, int b, int * path, int * path_len);
  13. int search_flow(int * graph, int n, int a, int b, int * flow);
  14. int search_min(int * graph, int n, int * path, int path_len);
  15. void update_flow(int * graph, int * flow, int n, int d, int * path, int path_len);
  16. void write_matching(int * flow, int n, const char * filename);
  17. void write_flow(int * flow, int n, int max_flow, const char * filename);
  18. void print_path(int * path, int n);
  19. int is_two_parts(int * graph, int * parts, int n);
  20.  
  21. int pop(int * queue, int * n);
  22. void push(int * queue, int * n, int value);
  23.  
  24. int main(){
  25.     int graph[MAX_SIZE][MAX_SIZE], flow[MAX_SIZE][MAX_SIZE], parts[MAX_SIZE]; // Матрица смежности графа
  26.     int n, a, b, i, j; // n - количество вершин. Из вершины a в вершину b ищем минимальный путь. max_flow - величина максимального потока
  27.    
  28.     int * ptr_graph = (int*)graph; // Указатель на матрицу смежности
  29.     int * ptr_flow = (int*)flow; // Указатель на поток
  30.    
  31.     read_graph(ptr_graph, &n, "in.txt"); // Считываем граф
  32.    
  33.     if (!is_two_parts(ptr_graph, parts, n)){
  34.         printf("It's not double-parts graph!");
  35.         return 1;
  36.     }
  37.    
  38.    
  39.    
  40. //  Добавляем в наш граф две вершины :
  41. //  Первую вершину (a) соединяем ребрами со всеми вершинами из parts, для которых parts[i] = 0
  42. //  Вторую вершину (b) соединяем ребрами со всеми вершинами из parts, для которых parts[i] = 1
  43.    
  44.     a = n - 2; b = n - 1; // Добавленные вершины
  45.    
  46. //  Добавляем соответствующие ребра
  47.     for(i = 0; i < n-2; i++){
  48.         *(ptr_graph+i*n+a) = *(ptr_graph+a*n+i) = parts[i];
  49.         *(ptr_graph+i*n+b) = *(ptr_graph+b*n+i) = 1 - parts[i];
  50.     }
  51.        
  52.     if (search_flow(ptr_graph, n, a, b, ptr_flow)) // Ищем максимальный поток
  53.         printf("The max matching has been successfully found!\n");
  54.     else
  55.         printf("The max matching does not exist!\n");
  56.    
  57. //  Удаляем из потока добавленные нами вершины:
  58.     for(i = 0; i < n; i++){
  59.         *(ptr_flow+i*n+a) = *(ptr_flow+a*n+i) = 0;
  60.         *(ptr_flow+i*n+b) = *(ptr_flow+b*n+i) = 0;
  61.     }
  62.    
  63. //  Записываем максимальное паросочетание из максимального потока в файл:
  64.     write_matching(ptr_flow, n, "out.txt");
  65.    
  66.     return 0;
  67. }
  68.  
  69. int is_two_parts(int * graph, int * parts, int n){
  70. //  Данная функция проверяет граф на двудольность и разбивает множество его вершин на две доли
  71. //  parts[i] = 0, если точка принадлежит одной доли, иначе 1, если принадлежит другой доли
  72.     int q[MAX_SIZE], q_len = 0, i; // Очередь для обработки вершин
  73.    
  74.     for(i = 0; i < n; i++)
  75.         parts[i] = -1; // Массив для чередования четности/нечетности вершин обнуляем
  76.    
  77.     push(q, &q_len, 0); parts[0] = 1; // Кидаем стартовую вершину и говорим, что она нечетная
  78.    
  79. //  Начинаем обрабатывать вершины
  80.     while (q_len) { // Пока не обработаны все вершины в очереди
  81.         const int t = pop(q, &q_len); // Вынимаем очередную вершину
  82.         for (i = 0; i < n; ++i) { // Обрабатываем все смежные с ней вершины
  83.             if (!*(graph+t*n+i)) continue; // Если нет ребра , то выходим
  84.             if (parts[i] == -1 ){ // Если ее еще никто не посетил
  85.                 parts[i] = 1-parts[t]; // Ставим у нее четность , противоположную четности той вершины , откуда пришли
  86.                 push(q, &q_len, i); // Ну и кидаем в очередь
  87.             } else if (parts[i] == parts[t])// Если четности двух соседних вершин совпали
  88.                 return 0; // То граф не двудольный
  89.         }
  90.     }  
  91.    
  92.     // Наш граф двудольный
  93.     return 1;
  94. }
  95.  
  96. void print_path(int * path, int n){
  97. //  Вывод пути на экран
  98.     int i;
  99.     for (i = 0; i < n; i++)
  100.         printf("%d ", path[i]);
  101.     printf("\n");
  102. }
  103.  
  104. int search_flow(int * graph, int n, int a, int b, int * flow){
  105.     int path[MAX_SIZE], path_len = 0, d;
  106.    
  107. //  Пока мы можем найти какой - либо путь из вершины а в вершину b
  108.     while (search_path(graph, n, a, b, path, &path_len)) {
  109.         d = search_min(graph, n, path, path_len); // Вычисляем минимальную длину ребра на этом пути
  110.         update_flow(graph, flow, n, d, path, path_len); // Обновляем матрицу смежности и матрицу потока на величину d
  111.     }
  112.    
  113. //  Дальше суммируем длинны всех исходящих из вершины а ребер . Это и будет величина нашего максимального потока
  114.     int max_flow = 0, i;
  115.     for (i = 0; i < n; ++i)
  116.         if (d = *(flow+a*n+i))
  117.             max_flow += d;
  118.    
  119. //  Возвращаем найденную нами величину максимального потока
  120.     return max_flow;
  121. }
  122.  
  123. int search_min(int * graph, int n, int * path, int path_len){
  124. //  Данная функция ищет минимальную длину среди длин всех ребер маршрута path
  125.     int i = 0, d, min;
  126.     min = *(graph+path[i]*n+path[i+1]);
  127.     for (i = 1; i < path_len - 1; i++)
  128.         if (min > (d = *(graph+path[i]*n+path[i+1])))
  129.             min = d;
  130.     return min;    
  131. }
  132.  
  133. void update_flow(int * graph, int * flow, int n, int d, int * path, int path_len){
  134. //  Данная функция обновляет ребра маршрута path в матрице смежности graph и матрице потока flow на величину d
  135.     int i;
  136.     for (i = 0; i < path_len - 1; i++){
  137.         int a = path[i], b = path[i+1];
  138.         *(graph+a*n+b) -= d; // Вычитаем из длины ребра a -> b величину d
  139.         *(graph+b*n+a) -= d; // По одному и тому же ребру в этом случае не ходим
  140.         *(flow+a*n+b) += d; // Прибавляем ее к длине ребра a -> b в нашем потоке
  141.     }
  142. }
  143.  
  144. void read_graph(int * graph, int * n, const char * filename){
  145. //  Открываем файл для чтения:   
  146.     FILE *fp;
  147.     fp = fopen(filename, "r");
  148.    
  149. //  Считываем оттуда количество вершин, вершину a и вершину b:
  150.     fscanf(fp, "%d", n);
  151.    
  152. //  Считываем оттуда матрицу смежности графа:
  153.     int i, j, k;
  154.     for (i = 0; i < *n; i++){
  155.         for (j = 0; j < *n; j++)
  156.             fscanf(fp, "%d ", graph+(*n+2)*i+j);
  157.         *(graph+(*n+2)*i+j)=0;
  158.         *(graph+(*n+2)*i+j+1)=0;
  159.     }
  160.    
  161.     for(k = 0; k < 2; k++)
  162.         for(j = 0; j < *n+2; j++)
  163.             *(graph+(*n+2)*(i+k)+j) = 0;
  164.     *n += 2;
  165. //  Закрываем файл
  166.     fclose(fp);
  167. }
  168.  
  169. int pop(int * queue, int * n){
  170. //  Вынимаем элемент из очереди
  171.     int t = queue[0], i;
  172.     *n -= 1;
  173.     for(i = 0; i < *n; i++)
  174.         queue[i] = queue[i+1];
  175.     return t;
  176. }
  177.  
  178. void push(int * queue, int * n, int value){
  179. //  Кладем новый элемент в очередь
  180.     queue[*n] = value;
  181.     *n += 1;
  182. }
  183.  
  184. int search_path(int * graph, int n, int a, int b, int * path, int * path_len){
  185. //  Ищем минимальный путь поиском в ширину
  186.     *path_len = 0; // Длина пути
  187.    
  188.     int visited[MAX_SIZE], q[MAX_SIZE]; // Посещенные вершины и очередь для посещения вершин
  189.     int q_len = 0, i, j; // Длина очереди и счетчики циклов
  190.    
  191.     for(i = 0; i < n; i++) // Обнуляем массив посещенны вершин
  192.         visited[i] = -1;
  193.            
  194. //  Кидаем стартовую вершину в очередь и запоминаем, что мы ее посетили:
  195.     push(q, &q_len, a);
  196.     visited[a] = a;
  197.    
  198. //  Пока мы не обработали необходимые вершины, обрабатываем их:
  199.     while (q_len > 0) {
  200. //      Вынимаем очередную вершину:
  201.         const int t = pop(q, &q_len);
  202. //      Если мы достигли необходимой вершины, то логично бы прекратить поиск
  203.         if (t == b) break;
  204. //      В цикле кидаем в очередь все непосещенные смежные с вершиной t вершины:
  205.         for (i = 0; i < n; i++)
  206. //          ЕСЛИ существтует ребро t -> i и ЕСЛИ мы по нему еще не прошли:
  207.             if (*(graph+t*n+i) && visited[i] == -1 ) {
  208.                 visited[i] = t; // Сохраняем в visited[i] вершину t, из которой мы пришли в вершину i
  209.                 push(q, &q_len, i); // Кидаем вершину i в очередь обработки
  210.             }      
  211.     }
  212.    
  213. //  Возвращаемся из вершины b в вершину a по тому пути , который мы запомнили в visited
  214.     while ( b != a && visited[b] != -1 ){
  215.         push(path, path_len, b); // Кидаем вершины в вектор пути
  216.         b = visited[b];
  217.     }
  218.  
  219. //  Если нам удалось дойти до стартовой вершины , то кидаем ее в наш путь
  220.     if ( b == a ) push(path, path_len, a);
  221.    
  222. //  Приведение пути к нормальному виду (переворачиваем его)
  223.     for (i = 0, j = *path_len-1; i < j; ++i,--j){
  224.         int temp = path[i];
  225.         path[i] = path[j];
  226.         path[j] = temp;
  227.     }  
  228.    
  229.     return *path_len; // Возвращаем длину найденного пути
  230. }
  231.  
  232. void write_matching(int * flow, int n, const char * filename){
  233. //  Запись максимального паросочетания в файл. Из записи необходимо исключить вершины a и b, так как они были добавлены нами искусственно для вычисления потока
  234.     FILE *fp;
  235.     fp = fopen(filename, "w");
  236.     int i, j;
  237.     for (i = 0; i < n; i++)
  238.         for (j = i+1; j < n; j++)
  239.             if (*(flow+n*i+j) || *(flow+n*j+i))
  240.                 fprintf(fp, "%d %d\n", i, j);
  241. }
  242.  
  243. void write_flow(int * flow, int n, int max_flow, const char * filename){
  244. //  Запись потока в файл
  245.     FILE *fp;
  246.     fp = fopen(filename, "w");
  247.     int i, j;
  248.     fprintf(fp, "%d\n", max_flow);
  249.     for (i = 0; i < n; i++, fprintf(fp, "\n"))
  250.         for(j = 0; j < n; j++)
  251.             fprintf(fp, "%d ", *(flow+i*n+j));
  252. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement