-1

I am trying to solve a problem that was given at an exam in a university in my country. It gives me as input a file that contains on the first line 3 numbers:

  • The first one(n) represents the number of people
  • The second one(m) represents the number of friendships between people
  • The third one(k) is the size of the sequence(but the sequence doesn't have to be exactly as large as this number, it can be bigger)
  • ...and on the second line the relations(m pairs of numbers with the form (a, b) meaning a is friend with b and b is friend with a).

    The task is to find the sequence with the maximum length(which is at least k people) in which people are friends with each other as efficiently as possible. If there is no such sequence "NO" will be printed.

    Their examples:

    data.txt:

    5 5 3
    1 2 5 1 3 2 4 5 1 4 
    

    output:

    1 4 5
    

    data.txt:

    5 5 4
    1 2 5 1 3 2 4 5 1 4 
    

    output:

    No
    

    data.txt:

    11 18 3 
    1 8 4 7 7 10 11 10 2 1 2 3 8 9 8 3 9 3 9 2 5 6 5 11 1 4 10 6 7 6 2 8 11 7 11 6 
    

    output.txt:

    2 3 6 7 8 9 10 11
    

    My approach

    Friendships in this case can be represented with an undirected graph (for me at least this seems the most logical data structure to use) where vertices represent people and edges represent friendships. To be part of the sequence a vertex needs to have a degree greater than or equal to k - 1.

    And that's where I stop. Currently all I can do is eliminate the nodes that don't have a degree of at least k - 1:

    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <utility>
    #include <algorithm>
    
    std::ifstream f{ "data.txt" };
    
    constexpr size_t LIMIT = 101;
    
    // graph[i][j]: i is friend with j
    // short to avoid vector<bool> specialization
    std::vector<std::vector<short>> graph(LIMIT, std::vector<short>(LIMIT, 0));
    std::vector<int> validNodes;
    
    int numOfNodes, numOfRelationships, sequenceSize;
    
    void Read()
    {
        f >> numOfNodes >> numOfRelationships >> sequenceSize;
    
        int a;
        int b;
    
        for(int i = 1; i <= numOfRelationships; ++i) {
            f >> a >> b;
    
            graph[a][b] = graph[b][a] = 1;
        }
    }
    
    int Degree(int node)
    {
        int result = 0;
    
        for(int i = 1; i <= numOfNodes; ++i) {
            if(i != node && graph[node][i] == 1) {
                ++result;
            }
        } 
    
        return result;
    }
    
    void KeepValidNodes()
    {
        for(int i = 1; i <= numOfNodes; ++i) {
            if(Degree(i) < sequenceSize - 1) {
                // Don't add the node to validNodes vector
                // "Remove it from the graph" aka it's not friend with anyone
                // all nodes that were friends with it now have a lower degree, remove them from the validNodes vector if that's the case
                for(int j = 1; j <= numOfNodes; ++j) {
                    auto findPos = std::find(validNodes.begin(), validNodes.end(), j);
    
                    if(findPos != validNodes.end() && Degree(j) - 1 < sequenceSize - 1) {
                        *findPos = -1;
                    }
    
                    graph[i][j] = graph[j][i] = 0;
                } 
            }
            else {
                validNodes.push_back(i);
            }
        } 
    }
    
    void PrintSequence()
    {
        bool empty = true;
    
        for(const int& node : validNodes) {
            if(node != -1) {
                empty = false;
                std::cout << node << std::endl;
            }
        }
    
        if(empty) {
            std::cout << "No" << std::endl;
        }
    }
    
    int main()
    {
        Read();
        KeepValidNodes();
        PrintSequence();
    }
    

    This works only for their first 2 examples. The only possible solution that I could think of is generating all possible combinations of nodes and see which one satisfies the requirements. How can I solve this problem efficiently as they say?

    EDIT:

    I am not necessarily looking for a fully working code but I don't even know how I could approach this problem.

    Alexandru Ica
    • 137
    • 2
    • 8

    1 Answers1

    3

    Your problem is about finding a clique of size k or smaller. I don't know if there are any algorithms capable of doing that, but there are certainly algorithms able to find maximum size clique. Once you find the maximum size clique (let's call it n-clique) in your graph, finding a clique of size <= n reduces to extracting a subset of vertices from n-clique.

    There is no polynomial time algorithm for the general case because this problem is NP-complete, so don't expect awesome results. This answer containts a short list of algorithms that will solve this problem quicker than brute-force algorithm. You should also take a look at Karp's paper on problem reducibility if you want to learn a little more about it (even if you don't apply this concept to that problem, it's worth reading because many solutions to NP-complete problems rely on reduction).

    An0num0us
    • 961
    • 7
    • 15