Раздел «Алгоритмы».HarmoniousGroup:

Задача "K-Harmonious group"

#include <cstdio>
#include <string>
#include <set>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;

int debug = 0; // установите в 1 для вывода отладочной 
               // информации 
#define M 20002
#define MP make_pair

vector< map<int,int > > adj;  /* adj - "матрица смежности" */
vector< map<int,int > > adj2; /* Копия adj */

map<string,int> id;   /* Отображение name->id */
map<int,string> name; /* Отображение id->name */

/* Множество пар (степень вершины, вершина)
 * set используется как очередь с приоритетами
 * Ключ - степень вершины, значение - идентификатор вершины
 */
set< pair<int,int> > q;
set< pair<int,int> > q2; // копия q для второго прохода

int m, n = 0;
int petr = 0;
string petr_name("Petr");

/* Возвращает целочисленный идентификатор вершины по её имени.
 * Если вершина новая, то добавляет её в словари name и id.
 * Хранилище строк с идентификаторами называется string pool 
 * или quark (см. Glib - http://library.gnome.org/devel/glib/stable/glib-data-types.html).
 */
int getid(string s) {
   if( id.find(s) == id.end() ) {
        // если имени нет в словаре, то добавим его туда,
        // назначив ему следующий порядковый идентификатор
        id[s] = n;
        name[n] = s;
        return n++;
    } else {
        // иначе вернем идентификатор человека с таким именем
        return id[s];
    }
}
/* По идентификатору строки находит саму строку 
 * (в данной задаче не используется)
 */
string getname(int id) {
  return name[id];
}

int main( ) {
    scanf("%d", &m); // считываем число рёбер 

    adj.resize(2 * m); // число вершин не более чем 2 * m
    for ( int i = 0 ; i < m ; i++ ) {
        char s[50],d[50]; // имена вершин (source,destination)
        string ss, dd;    // их string-овый вариант
        int s_id, d_id;   // и их целочисленные идентификаторы
        scanf("%s%s", s, d);
        ss = s;  // В этих строчках происходит копирование 
                 // содержания строк, а не их адресов.
        dd = d;  // Дело в том, что оператор присвоения (=) 
                 // переопределён для случая, 
                 // когда справа стоит char*, а слева string.

        s_id = getid(ss);
        d_id = getid(dd);

        if ( adj[s_id].find(d_id) != adj[s_id].end() ) {
            fprintf(stderr, "Duplicate: %s %s\n", s, d);
        }
        if ( s_id == d_id ) {
            fprintf(stderr, "Equal     : %s %s\n", s, d);
        }
        adj[d_id][s_id] = 1;
        adj[s_id][d_id] = 1;
    }

    petr = getid(petr_name);

    for ( int i = 0 ; i < n ; i++ ) {
        q.insert( MP(adj[i].size(), i) );
    }

    q2 = q;     // Создадим копии для второго прохода
    adj2 = adj; //   

    int max_degree = (*(q.begin())).first;
    int degree, a;
    while ( q.size() ) {
        /* извлекаем  вершину с минимальной степенью ("слабое 
       звено" - работник, у которого меньше всего друзей) */
        degree = (*(q.begin())).first;
        a      = (*(q.begin())).second;
        /* Дело в том, что set.first() возвращает _наименьшую_
       пару. Порядок на парах, совпадает с порядком на первом
       элементе. Первый элемент нашей пары - степень вершины. 
        Таким образом, set может использоваться для реализации 
        функциональности очереди с приоритетом.*/
        if ( debug ) 
            printf("Max degree=%d\nExtracting %s with %d\n\n", 
                       max_degree, name[a].c_str(), degree);

        if ( max_degree < degree ) {
            max_degree = degree;
        }
        if ( a == petr ) break;

        // удаляем "слабое звено"
        q.erase(q.begin());

        // и "подчищаем" все его "дружбы"
        map<int, int> friends = adj[a];
        map<int,int>::iterator it;
        for(it = friends.begin();it != friends.end();it++) {
            int b = (*it).first;
            q.erase( MP(adj[b].size(), b ) );
            adj[b].erase(a);
            q.insert( MP(adj[b].size(), b) );
        }
    }

    if (debug) {printf("Final max degree=%d\n", max_degree);}
    
    /* Итак, мы узнали  максимальное значение "стабильности".
      Теперь повторим все сначала, уже печатая ответ.  */
    while ( q2.size() ) {
        degree = (*(q2.begin())).first;
        a      = (*(q2.begin())).second;
        if ( degree >= max_degree ) {
            break;
        }
        q2.erase( q2.begin() );
        if ( debug ) 
           printf("Max degree=%d\nExtracting %s with %d\n\n",
                   max_degree, name[a].c_str(), degree);

        map<int,int> friends = adj2[a];
        map<int,int>::iterator it;
        for (it = friends.begin();it != friends.end();it++) {
            int b = (*it).first;
            q2.erase( MP(adj2[b].size(), b ) );
            adj2[b].erase(a);
            q2.insert( MP(adj2[b].size(), b) );
        }
    }
    // Выводим размер коллектива и его стабильность
    printf("%d %d\n", q2.size(), max_degree);
    set<string> answer; // шаблон set можно использовать 
                        // для сортировки;
    {
        set< pair<int,int> >::iterator j;
        for ( j = q2.begin(); j != q2.end() ; j++ ) {
            answer.insert( name[((*j).second)]  );
        }
    }
    {
        set<string>::iterator j;
        for ( j = answer.begin(); j != answer.end() ; j++ ) {
            printf("%s ", (*j).c_str() );
        }
    }
    printf("\n");
    return 0;
}
AlgorithmClasifyForm
Type: Код
Scope: Графы, Структуры данных, STL
Strategy: Жадность
Language: C++
Complexity: Medium

Attachment sort Action Size Date Who Comment
K-Harmonious_group.pdf manage 314.6 K 24 Jun 2008 - 09:56 ArtemVoroztsov