Dwarf Tower#6263

Dwarf Tower (Editorial)

Build a graph in the form of an adjacency list , where contains pairs of numbers such that items and can be combined to produce item : (i, j) \to a.

Let be an array initially containing the purchase costs of the items (cost[i] = c_i). By the end of the algorithm will store the minimum amount of money required to obtain item .

Initially, all items are considered unprocessed (used[i] = 0).

While there is at least one unprocessed item:

For each rule (a, b) \to to from we recompute

cost[to] = min(cost[to], cost[a] + cost[b])

Example

Consider the first test. There are items with the following purchase costs:

There are three item crafting rules. Let's build an adjacency list based on them.

Item has the smallest cost: cost[2] = 0. Apply all rules involving item , namely those listed in . After that, mark item as processed.

The next unprocessed item with the smallest cost is . Apply the rules listed in . The costs of the items do not change in this step.

Next, the unprocessed item with the smallest cost becomes item . Apply the rule from .

In the subsequent operations, the costs of the items do not change. Thus, the minimum cost to obtain item is .

Algorithm implementation

Declare the arrays. Declare an adjacency list , which will contain the item crafting rules.

vector<int> cost, used;
vector<vector<pair<int, int>>> g;

Read the input data. Initialize the arrays.

scanf("%d %d", &n, &m);
g.resize(n + 1);
cost.resize(n + 1);
used.resize(n + 1);

Read the purchase costs of the items.

for (i = 1; i <= n; i++)
  scanf("%d", &cost[i]);

Read the item crafting rules and build an adjacency list based on them.

for (i = 0; i < m; i++)
{
  scanf("%d %d %d", &a, &x, &y);
  g[x].push_back(make_pair(y, a));
  g[y].push_back(make_pair(x, a));
}

Perform iterations.

for (k = 0; k < n; k++)
{

In each iteration, among the unprocessed items, find the one with the smallest cost. Let this be the item with number .

  mn = 2e9; a = -1;
  for (i = 1; i <= n; i++)
    if (!used[i] && cost[i] < mn)
    {
      mn = cost[i];
      a = i;
    }

Mark item as processed.

  used[a] = 1;

Iterate through all rules involving item .

      for (auto x : g[a])
      {
         b = x.first;
         to = x.second; // (a, b) -> to
         if (cost[a] + cost[b] < cost[to]) cost[to] = cost[a] + cost[b];
  }
}

Print the minimum amount of money required to purchase the first item.

printf("%d\n", cost[1]);

Python implementation

In Python, is a special value representing infinity. It is available in the module, which must be imported to use it.

from math import inf

Read the input data.

n, m = map(int, input().split())
cost = [0] + list(map(int, input().split()))

Initialize the lists.

used = [False] * (n + 1)
g = [[] for _ in range(n + 1)]

Read the item crafting rules and build an adjacency list based on them.

for _ in range(m):
  a, x, y = map(int, input().split())
  g[x].append((y, a))
  g[y].append((x, a))

Perform iterations.

for k in range(n):

In each iteration, among the unprocessed items, find the one with the smallest cost. Let this be the item with number .

  mn = inf
  a = -1
  for i in range(1, n + 1):
    if not used[i] and cost[i] < mn:
      mn = cost[i]
      a = i

Mark item as processed.

  used[a] = True

Iterate through all rules involving item .

  for b, to in g[a]:
    if cost[a] + cost[b] < cost[to]:
       cost[to] = cost[a] + cost[b]

Print the minimum amount of money required to purchase the first item.

print(cost[1])