Teads Sponsored Puzzle

That’s what I did in Java and it works fine. I don’t think you need to build the graph that way, keep things to what you need, no more.
You can see it like: A graph is just nodes that are linked to other nodes.

How can you do that and easily add and especially remove a node? Using this strategy, when you remove a leaf (i.e. node with only one edge), you do not want to check every node of the graph to see if it’s linked to the node you remove. What you want is: okay, I will remove this node, so for every node it is linked (and I already know who they are), I’ll remove the link.

1 Like

If you timeout just by creating the graph, you are doing it so wrong. C# is clearly fast enough to do that so you may have a problem.

Yeah, I think I am doing it wrong. I timeout by creating the graph only on the 2 biggest tests: 8 and 9. My previous brute force solution failed 7, 8 and 9, So there is “some kind” of optimisation. But it is wrong somehow

Can you just show how you create your graph ? Don’t post the full code (it’s forbidden), just the creation of the graph.

hi magus,

Thanks. In my main, I do:

class Solution
{
    static void Main(string[] args)
    {
        Graph<int> personGraph = new Graph<int>(); 
        int n = int.Parse(Console.ReadLine()); // the number of adjacency relations
        for (int i = 0; i < n; i++)
        {
            string[] inputs = Console.ReadLine().Split(' ');
            int xi = int.Parse(inputs[0]); // the ID of a person which is adjacent to yi
            int yi = int.Parse(inputs[1]); // the ID of a person which is adjacent to xi
            personGraph.AddEdge(xi, yi, 0);
        }
        {...}
    }
}

My graph class (with only the relevant 2 Method visible):

public class Graph<T> //: IEnumerable<T>
{
    private NodeList<T> nodeSet;

    public Graph() : this(null) {}
    public Graph(NodeList<T> nodeSet)
    {...}

    public void AddNode(GraphNode<T> node)
    {
        // adds a node to the graph
        nodeSet.Add(node);
    }

    public void AddNode(T value)
    {...}
    
    public void AddEdge(T fromVal, T toVal, int cost)
    {
        GraphNode<T> from = nodeSet.FindByValue(fromVal) as GraphNode<T>;
        if (from == null)
        {
            from = new GraphNode<T>(fromVal);
            nodeSet.Add(from);
        }
        GraphNode<T> to = nodeSet.FindByValue(toVal) as GraphNode<T>;
        if (to == null)
        {
            to = new GraphNode<T>(toVal);
            nodeSet.Add(to);
        }
        from.Neighbors.Add(to);
        from.Costs.Add(cost);
        
        to.Neighbors.Add(from);
        to.Costs.Add(cost);
    }

    public bool Contains(T value)
    {
        return nodeSet.FindByValue(value) != null;
    }

    public bool Remove(T value)
    {...}
    
    public int RemoveExernalNodes()
    {...}

    public NodeList<T> Nodes
    {...}

    public int Count
    {...}
}

I could simplify my whole graph structure to has it less general (in the current construct, I have a Node class which encapsulates my node data and its neighbours as a NodeList. The NodeList derives from a Collection of Node and a GrpahNode class which inherits from Node to handl directed edges and weight (not needed here, I try to remove them but it did not show mnuch improvement).

Ok i understand why you are so slow. FindByValue is slow. Because it will search into the whole set the find your element (actually it will not browse the whole set because it is optimized, but it’s slow, anyway).

Maybe i’ll do some error because i’m not an expert at C#, but this is what i do:

  • First of all, read the input to know how many nodes you will need. Let’s call this value N. Don’t forget to store inputs in a List or an array.

  • You only need one class, this one:

     public class Node {
         private int id;
         private List<Node> nodes;
    
         // Constructors, methods, bla bla bla
     }
    
  • Now, you just have to create an array of Node: Node[] nodes = new Node[N]; And don’t forget to initialize all your nodes

     for (int i = 0; i < N; i++) {
         nodes[i] = new Node(i + 1); // Node id in the input start at 1, not 0
     }
    
  • To create your graph, re-read the inputs to add edges like this:

     nodes[xi - 1].getNodes().add(nodes[yi - 1]);
     nodes[yi - 1].getNodes().add(nodes[xi - 1]);
    

You have your graph.

4 Likes

Sounds “easy enough”. I did not know of the performance drawback of “FindByValue”. Thanks for the hint. I shall give uit a try :wink:

Nice thanks for the tip, I think I’ve the same issue with Java. I’m having timeouts for tests 8 and 9.
For test 7 which is the largest I pass, debug tells me:
Duration for init: 57
Duration for compute: 1
Duration for checkCurrentBestNodeBalanced: 0
Total duration: 58

This is ridiculous to spend 99% in the init part (graph construction). I guess indexOf in Java is as slow as FindByValue in C#. I’ll give it a new try and change some lists for some arrays.

Java and C# are pretty much the same. So yes, indexOf of a list or a set is as slow as FindByValue. No one can beat an array for that :smiley:

Well yeah with arrays for init on case 7 it’s now much better:
Duration for init: 37
Duration for compute: 1
Duration for checkCurrentBestNodeBalanced: 0
Total duration: 39

For the largest one (9):
Duration for init: 219
Duration for compute: 7
Duration for checkCurrentBestNodeBalanced: 0
Total duration: 226

No idea if it’s good or not, but my algo (which is NOT the leaf cutting discussed in this thread) looks not that bad for execution time…
By the way, funny I had not realized earlier the number of nodes is just number of link +1, whatever the way they’re linked…

Yeah, it worked \o/. You were right, from the moment I stopped “searching” it went all smoother. The c# stopwatch tells me a duration of approximately 80ms to compute the right result for the test 9 :wink:

1 Like

That’s perfectly normal, since the graph is a tree.

2 Likes

Hello, I need some information for the Teads Sponsored Puzzle.I use C. I passed the first 7 cases but when it’s about the 8th, I get an error while initializing my adjacency matrix. Then and I tested that initialization for several values of n -number of nodes-, for values of n above 6000 I get an segmentation fault. Does someone has an explanations for that?

Salut, j’ai besoin d’information concernant le Teads Sponsored Puzzle. J’utilise le langage C. Mon programme fonctionne pour les 7 premiers tests mais au huitième j’ai une erreur juste à l’initialisation de ma matrice d’adjacence. J’ai alors tester avec plusieurs valeur du paramètre n (le nombre d’arêtes), et pour les valeurs supérieures ou égale à 6000 j’ai une erreur de segmentation. Quelqu’un aurait une explication?

Maybe your matrix is too big.

I see, I didn’t think that too big matrix could lead to a segmentation fault. I guess I’ll be obliged to use adjacency lists instead of adjacency matrix

There has to be a more elegant way to do this, but this was my solution:

I did this using two main processes: an outer process that picks nodes to test, and an inner process that broadcasts the message and counts relays. In both of the processes I maintain lists of nodes that have already been tested or relayed, so that I don’t end up re-testing/re-counting nodes.

For the outer process:
I started with the node with the highest number of neighbors as the first node.
Run the inner process (see below), and store the number of relays as the starting “minimum relays”

Then:

  1. Run the inner process for each of the neighbors of that node, keeping track of the number of relays for each.
  2. If any of those nodes are lower than the current minimum relays, the lowest of those becomes the source node for the next set of nodes to test.
  3. Repeat until all viable nodes have been tested
    By doing this, you’re targeting each test at a better node, narrowing down the list each time.

For the inner process:

  • I created two loops: one that loops through a “current nodes” list, and one that adds nodes to a “next nodes” list, based on each of the “current nodes.”
  • For each iteration through the complete “current nodes” list, I increment a relay counter.
  • If at any time the relay counter becomes greater than the current “minimum relays”, I break out of the process.
  • At the end of the loop, the “next nodes” list becomes the “current nodes” list.
  • Repeat until all nodes have been relayed.
1 Like

Are all the graphs in the testcases connected? Or is it possible that some of them are disconnected?

Thanks,
Adam

I solved the puzzle with a different method, however I’d just like to point out that the 10th test expects a wrong value: 5 instead of 4 :slightly_smiling:
(This just happens in testing, while submitting the code there’s no issue)
Happy coding!

I had this problem solved in 2 different ways, and never seen a wrong value. Something should be wrong with your code.

2 Likes

Hi everyone !

I am having a little problem on this puzzle : My algorithm succeeds on cases 1 to 6, and in case 10.
However, it finds incorrect values (too small) on cases 7, 8 and 9. Because of the size of the last 3 datasets, it is hard to figure out what went wrong. Is there an easy way to see the tree on a “graphical” way so that i can understand at what point the algorithm fails ?

Thanks!


Bonjour à tous !

J’ai un petit problème sur cet exercice : Mon algorithme fonctionne correctement sur les cas 1 à 6 et sur le 10, mais trouve des valeurs incorrectes (trop petites) sur les cas 7, 8 et 9. Vu la taille des jeux de données, j’ai du mal à trouver le problème. Est-ce qu’il existe un moyen pratique de voir les graphes de manière plus “visuelle” pour que je puisse voir à quel moment mon algorithme plante ?

Merci !