Блог пользователя chrome

Автор chrome, история, 9 лет назад, По-русски

Всем привет!

Сегодня в 19:00 MSK состоится Topcoder SRM 685.

Приглашаю всех к участию и предлагаю обсудить задачи здесь после контеста.

  • Проголосовать: нравится
  • +173
  • Проголосовать: не нравится

»
9 лет назад, # |
  Проголосовать: нравится +94 Проголосовать: не нравится

Problem 450 is very creative:

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится +10 Проголосовать: не нравится

    Ok, more serious now: if we don't use the above theorem, what is expected solution? I can only think of brute force 1 spanning tree & check if another exist, but the complexity in worst case is N(N - 2) * N2 = NN which seems too big..

    • »
      »
      »
      9 лет назад, # ^ |
        Проголосовать: нравится +37 Проголосовать: не нравится

      I randomly generate a permutation of m edges and greedily (like Kruskal) find a spanning tree, then check if the remaining edges are valid. I do this for 300000 times and it passed ST. Maybe it's hard to generate testcases against this approach.

      • »
        »
        »
        »
        9 лет назад, # ^ |
        Rev. 2   Проголосовать: нравится +35 Проголосовать: не нравится

        If there is a solution with 18 edges, then any random permutation where the 9 edges belonging to the first partition are before the 9 edges of the second partition works. The probability of getting permutation like this is at least . Therefore the probability of failing if you do 300000 iterations is at most .

    • »
      »
      »
      9 лет назад, # ^ |
      Rev. 2   Проголосовать: нравится +197 Проголосовать: не нравится

      Since you only need two trees you can do this
      iterate through the edges and hold 2 dsu's
      assume that the edge is u-v if find(u, firstdsu) == find(v, firstdsu) then we do not need this edge in the firstdsu and we will use it in the second dsu
      likewise if find(u, seconddsu) == find(v, seconddsu) we just merge(u, v) in the first dsu
      if neither of these happen we just check the both ways (adding the edge in the first dsu or the second one) since this doesnt happen more than 2 ^ (2n — 2) (the number of times we get an edge that reduces the number of components) times we can say the program is of O(2 ^ (2n — 2) * m * dsuOperation)

      • »
        »
        »
        »
        9 лет назад, # ^ |
          Проголосовать: нравится +46 Проголосовать: не нравится

        I just have to comment by saying this is an awesome solution. It almost makes me not angry by the fact that this was a googleable problem :P

      • »
        »
        »
        »
        9 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        Didn't understand :| A little explanation please?

        • »
          »
          »
          »
          »
          9 лет назад, # ^ |
            Проголосовать: нравится +5 Проголосовать: не нравится

          i edited my explanation maybe it was because of the typo's (either -> neither) if you wanted more explanations please tell

    • »
      »
      »
      9 лет назад, # ^ |
        Проголосовать: нравится +36 Проголосовать: не нравится

      I believe the intended solution is bell-number DP.

      For example, dp[{{1, 3, 6}, {2, 5}, {0}}] is true iff we can divide edges among {0, 1, 2, 3, 5, 6} into two groups such that

      • In the first group, all current vertices (0, 1, 2, 3, 5, 6) are connected.
      • In the second group, there are three connected components: {1, 3, 6}, {2, 5}, {0}.

      This solution will work in O(bell_number(N) * poly(N)).

    • »
      »
      »
      9 лет назад, # ^ |
      Rev. 2   Проголосовать: нравится +30 Проголосовать: не нравится

      Hmm, I'm a bit surprised that no one mentioned the intended solution. Note that both testers come up with that first. (EDIT: it was mentioned above by Reyna)

      Consider edges one by one, each time you have 2 choices: add it to graph 1 or graph 2.

      Note that if add it to graph 1 no longer reduce the number of connected components, but add it to graph 2 can reduce the number of connected components, then we just add it to graph 2.

      With this pruning, the running time will be O(C(2n, n) * m).

      • »
        »
        »
        »
        9 лет назад, # ^ |
          Проголосовать: нравится +8 Проголосовать: не нравится

        This was mentioned above by Reyna and it think it's pretty cool.

        However, I'm wondering whether anyone tried to google this problem during testing?

        • »
          »
          »
          »
          »
          9 лет назад, # ^ |
            Проголосовать: нравится +8 Проголосовать: не нравится

          I Googled it with keywords like "split graph into two connected graphs" and so on, instead of searching things related to "spanning tree".

      • »
        »
        »
        »
        9 лет назад, # ^ |
          Проголосовать: нравится +48 Проголосовать: не нравится

        If I understand correctly, the problem was to find 2 non-intersecting trees in a graph. It can be solved in polynomial time. Moreover, finding k non-intersecting trees can be done in time of (nk)^3.

        We can think in a problem in such way. Lets color each edge in it's own color, and copy graph k times. Then we need to find acyclic subgraph in which all colors are different. Both this conditions on sets form a matroid.

        We can find biggest set which lies in two matroids using matroid intersection algorithm

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Nash-Williams-Tutte's theorem, afaik. Here is some paper.

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится +62 Проголосовать: не нравится

    Yeah, for me the algorithm of solving this problem was

    1. Try to come up with smth by myself.
    2. Type "two spanning trees" in Google.
    3. Go to the first link and read the solution there.
»
9 лет назад, # |
Rev. 3   Проголосовать: нравится +9 Проголосовать: не нравится

»
9 лет назад, # |
Rev. 2   Проголосовать: нравится +10 Проголосовать: не нравится

Looks like problem setter was studying spanning tree theorems when he came up with this round...

For div1 450, I thought about partitioning, but I only considered partitions into 2 sets and checking if edges between partitions were at least 2, not all partitions... I doubt I would be convinced that it would work even if I thought of the all partitions idea.

»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Как решить див2 500?

  • »
    »
    9 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится +12 Проголосовать: не нравится

    Я хранил для каждой вершины set<pair<int, int>> — множество длин путей, заканчивающихся в ней. Потом n - 1 раз проходил по всем ребрам, и для каждого добавлял в v все пути из u с дописанным ребром (u, v) — как-то так:

    for (u, v: edges) {
        for (auto p: lengths[u]) {
            a = weight1[u][v] - '0';
            b = weight2[u][v] - '0';
            lengths[v].insert(p.first + a, p.second + b);
        }
    }
    

    Больше, чем n - 1 раз, делать это не нужно, т.к. на каждой итерации длина пути растет на 1, а несамопересекающегося пути из N ребер не бывает. Остается только выбрать оптимальный из путей в lengths[1]. Если пути нет, то множество будет пусто — выводим -1.

    Всего различных весов путей из не более чем 20 ребер бывает не больше 9*20 = 180, итого в вершине хранится не больше 180^2 = 3.2*10^4 пар. Всего действий порядка N * N^2 * (9N)^2, да еще на логарифм, что вообще-то многовато (~3.8*10^9 при N = 20), но оценка на количество путей весьма и весьма верхняя, так что все заходит. Точнее, наоборот: я сделал вывод, что это завышенная оценка, потому что зашло :)

»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Is there a way to check who is the author of this contest? It contained some graph problems that I found very interesting, so I want to check his previous rounds on CF/TC.

»
9 лет назад, # |
  Проголосовать: нравится +56 Проголосовать: не нравится

The hard problem is exactly the same as this one(in Chinese).

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится +16 Проголосовать: не нравится

    Thanks for the info. That explains why matthew99 can solve it so quickly. :)

    And it seems I need to read all tasks in that OJ.

»
9 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

cgy4ever What is the problem in running simple dfs for div 2 500 ? My solution with simple dfs. I find many submissions getting wrong answer for this. Can you please explain what is the right approach for this problem ?

  • »
    »
    9 лет назад, # ^ |
    Rev. 6   Проголосовать: нравится +6 Проголосовать: не нравится

    "Simple dfs" is essentially a greedy solution. You visit each vertex at most once and if you were not lucky enough to find the correct path at the first try you won't ever consider other paths to a vertex. A small counterexample is

    ..91
    ..11
    91.1
    111.
    

    As is often the case, dynamic programming works in this problem while greedy does not. Try to find a state of the form (last_visited_vertex, something_else).

    UPD. I've read your solution one more time. What you wrote is in fact a backtracking solution that has a misleading name 'dfs'. Your mistake is probably that in some cases you forget to set back vis[u] to false in the loop. Such exhaustive search should not work for this problem because of its high time complexity but the top-scoring solution suggests that it could work if you add some pruning.

    • »
      »
      »
      9 лет назад, # ^ |
      Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

      Could you solve this problem by using Dijkstra's algorithm on the first graph, then follow the same path for the second graph?

      • »
        »
        »
        »
        9 лет назад, # ^ |
        Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

        Shortest path in one graph will not lead to optimal answer (least product of total path length in two graphs). Hence this strategy won't work. As the constraints were small, I used floyd-warshall algorithm to solve it.

        for(from=0;from<vertices;from++)
            for(to=0;to<vertices;to++)
                for(via=0;via<vertices;via++)
                    if(w1[from][to] * w2[from][to] > 
                         (w1[from][via]+w1[via][to]) * 
                             (w2[from][via]+w2[via][to])){
                        w1[from][to]=w1[from][via]+w1[via][to];
                        w2[from][to]=w2[from][via]+w2[via][to]; 
                    }
        ans=w1[0][1] * w2[0][1];
        
»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Where does one public editorials on topcoder.com ?

»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Can anybody please explain how to do div 2 900?

»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Can anybody please explain, how to solve div 2 900?

  • »
    »
    9 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

    Dynamic Programming or Memoization with BitMasks.( E * (2 ^ N) * (5 ^ 3) )

    State is (msk,r,g,b). Your return value is a boolean.

    The mask represents nodes with degree bigger than zero.

    Suppose we have an edge connecting nodes u and v.

    An edge can only be added if at least one of deg(u) or deg(v) is zero to maintain growing a spanning tree. (

    We can only have up to (n-1) / 3 edges of each colour given the constraints, both r ,g and b cannot exceed 5. ( otherwise we just prune this impossible state. 2^13 * 13 * 13 * 13 will give MLE ( Java ) ).

    In our DP:

    Iterate over all edges, if it’s possible to add this edge, set both nodes it connects to 1 in the bitmask, increase r,g or b depending on the edge’s colour.

    After each step recurse further.

    Base case: When mask contains n 1’s it means we have used (n-1) edges which means our tree ready. Check if every colour in our state equals k / 3.

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Another solution for the problem could be something like this :

    Let us fix a root for the final spanning tree and to every other vertex assign a color (among the R/G/B). Since the root is fixed, we can associate each vertex with an edge (connecting the vertex with its parent) and assigning color to the vertex can be thought of as assigning color to the corresponding edge. Given such a configuration (a fixed root and a color for each node) we can check using simple bfs whether such a spanning tree is possible or not by starting at the fixed root and exploring only those edges which have the same color as the vertex explored by those edges.

    We can check all possible configurations which turns out to be O(n*3^(n-1)*|E|) which looks pretty large but since we need to check only those cases where number of edges of each color is same, a lot of the search space is pruned and it works well in time. You can have a look at this accepted solution for more details :

    http://pastebin.com/nhiNXWFq

»
9 лет назад, # |
  Проголосовать: нравится +8 Проголосовать: не нравится

Does anybody have the solution for div1 hard which he can prove?

  • »
    »
    9 лет назад, # ^ |
    Rev. 4   Проголосовать: нравится +5 Проголосовать: не нравится

    Can anybody tell the idea of the problem?

    Does it has something to do with eigen values of the Laplacian matrix?

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится +10 Проголосовать: не нравится

    I haven't implemented it but I guess we can do the following:

    Let g be the primitive root of 109 + 7.

    For each x = g0, g1, ..., g29999 and x = g0, g30000, ..., g999990000 generate a tree with up to 150 vertices and x MSTs. (I'm not completely sure but we can find these trees like the original problem)

    Connect them with an edge.

    • »
      »
      »
      9 лет назад, # ^ |
      Rev. 2   Проголосовать: нравится +15 Проголосовать: не нравится

      Yes, that would lead to a proof that is 'not too long'. (obviously you can run your program for all 109 + 7 inputs to get a proof, but it may take years.)

      My proof is like this:

      1. Generate 20000 random graph with 10 nodes, for each of them compute Discrete logarithm of number of MST, so we get a list of 20000 numbers.

      2. Then for each pair of number in this list, add sum to a new list, so we get a new list of 200002 numbers.

      3. Find the minimal gaps between numbers in that list. In my case, it is 118.

      4. So my graph will have no more than 10 + 10 + (118/3) * 5 + (118%3) * 5 = 220 nodes. (A cycle with length 5 has g1 MST, and a clique of size 5 has g3 MST)

      My program needs to run about 2 minutes with 2GB of memory.