Post

UVa506 - System Dependencies

UVa506 - System Dependencies

题设

Components of computer systems often have dependencies—other components that must be installed before they will function properly. These dependencies are frequently shared by multiple components. For example, both the TELNET client program and the FTP client program require that the TCP/IP networking software be installed before they can operate. If you install TCP/IP and the TELNET client program, and later decide to add the FTP client program, you do not need to reinstall TCP/IP.

For some components it would not be a problem if the components on which they depended were reinstalled; it would just waste some resources. But for others, like TCP/IP, some component configu- ration may be destroyed if the component was reinstalled.

It is useful to be able to remove components that are no longer needed. When this is done, compo- nents that only support the removed component may also be removed, freeing up disk space, memory, and other resources. But a supporting component, not explicitly installed, may be removed only if all components which depend on it are also removed. For example, removing the FTP client program and TCP/IP would mean the TELNET client program, which was not removed, would no longer operate. Likewise, removing TCP/IP by itself would cause the failure of both the TELNET and the FTP client programs. Also if we installed TCP/IP to support our own development, then installed the TELNET client (which depends on TCP/IP) and then still later removed the TELNET client, we would not want TCP/IP to be removed.

We want a program to automate the process of adding and removing components. To do this we will maintain a record of installed components and component dependencies. A component can be installed explicitly in response to a command (unless it is already installed), or implicitly if it is needed for some other component being installed. Likewise, a component, not explicitly installed, can be explicitly removed in response to a command (if it is not needed to support other components) or implicitly removed if it is no longer needed to support another component. Installing an already implicitly-installed component won’t make that component become explicity installed.

Input

The input file contains several test cases, each of them as described below. The input will contain a sequence of commands (as described below), each on a separate line containing no more than eighty characters. Item names are case sensitive, and each is no longer than ten characters. The command names (DEPEND, INSTALL, REMOVE and LIST) always appear in uppercase starting in column one, and item names are separated from the command name and each other by one or more spaces. All appropriate DEPEND commands will appear before the occurrence of any INSTALL command that uses them. There will be no circular dependencies. The end of the input is marked by a line containing only the word END.

Command SyntaxInterpretation/Response
DEPEND item1 item2 [item3 …]item1 depends on item2 (and item3 …)
INSTALL item1install item1 and those on which it depends
REMOVE item1remove item1, and those on which it depends, if possible
LISTlist the names of all currently-installed components

Output

For each test case, the output must follow the description below. Echo each line of input. Follow each echoed INSTALL or REMOVE line with the actions taken in response, making certain that the actions are given in the proper order. Also identify exceptional conditions (see Sample Output, below, for examples of all cases). For the LIST command, display the names of the currently installed components in the installation order. No output, except the echo, is produced for a DEPEND command or the line containing END. There will be at most one dependency list per item.

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
DEPEND   TELNET TCPIP NETCARD
DEPEND TCPIP NETCARD
DEPEND DNS TCPIP NETCARD
DEPEND  BROWSER   TCPIP  HTML
INSTALL NETCARD
INSTALL TELNET
INSTALL foo
REMOVE NETCARD
INSTALL BROWSER
INSTALL DNS
LIST
REMOVE TELNET
REMOVE NETCARD
REMOVE DNS
REMOVE NETCARD
INSTALL NETCARD
REMOVE TCPIP
REMOVE BROWSER
REMOVE TCPIP
END

Sample Output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
DEPEND   TELNET TCPIP NETCARD
DEPEND TCPIP NETCARD
DEPEND DNS TCPIP NETCARD
DEPEND  BROWSER   TCPIP  HTML
INSTALL NETCARD
   Installing NETCARD
INSTALL TELNET
   Installing TCPIP
   Installing TELNET
INSTALL foo
   Installing foo
REMOVE NETCARD
   NETCARD is still needed.
INSTALL BROWSER
   Installing HTML
   Installing BROWSER
INSTALL DNS
   Installing DNS
LIST
   NETCARD
   TCPIP
   TELNET
   foo
   HTML
   BROWSER
   DNS
REMOVE TELNET
   Removing TELNET
REMOVE NETCARD
   NETCARD is still needed.
REMOVE DNS
   Removing DNS
REMOVE NETCARD
   NETCARD is still needed.
INSTALL NETCARD
   NETCARD is already installed.
REMOVE TCPIP
   TCPIP is still needed.
REMOVE BROWSER
   Removing BROWSER
   Removing HTML
   Removing TCPIP
REMOVE TCPIP
   TCPIP is not installed.
END

题解

这道题按照题意模拟即可,需要维护的有以下内容:一个组件和一个编号的双向对应关系、父组件对应的子组件(依赖于)、子组件对应的父组件(被依赖)、安装的组件列表、组件是否安装。这些均在全局变量中体现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <algorithm>
#include <iostream>
#include <sstream>
#include <unordered_map>
#include <vector>
using namespace std;
const int N = 100010;

int idx;

string dict1[N];
unordered_map<string, int> dict2;
vector<int> s[N];
vector<int> p[N];
int st[N];
vector<int> list;

int get_idx(const string& w) {
  if (!dict2.count(w)) {
    dict1[++idx] = w;
    dict2[w] = idx;
  }
  return dict2[w];
}

void depend(istringstream& iss) {
  string word;
  iss >> word;
  int num = get_idx(word);
  int num2;
  while (iss >> word) {
    num2 = get_idx(word);
    s[num].push_back(num2);
    p[num2].push_back(num);
  }
}

void install_helper(int num, int type) {
  for (auto& it : s[num])
    if (!st[it]) install_helper(it, 1);
  list.push_back(num);
  st[num] = type;
  cout << "   Installing " << dict1[num] << '\n';
}

void install(const string& w) {
  int num = get_idx(w);
  if (st[num])
    cout << "   " << w << " is already installed.\n";
  else
    install_helper(num, 2);
}

void remove_helper(int num) {
  for (auto& it : p[num])
    if (st[it]) return;
  st[num] = 0;
  list.erase(find(list.begin(), list.end(), num));
  cout << "   Removing " << dict1[num] << '\n';
  for (auto& it : s[num])
    if (st[it] == 1) remove_helper(it);
}

void remove(const string& w) {
  int num = get_idx(w);
  if (!st[num]) {
    cout << "   " << w << " is not installed." << '\n';
    return;
  }
  for (auto& it : p[num])
    if (st[it]) {
      cout << "   " << w << " is still needed." << '\n';
      return;
    }
  st[num] = 0;
  list.erase(find(list.begin(), list.end(), num));
  cout << "   Removing " << dict1[num] << '\n';
  for (auto& it : s[num])
    if (st[it] == 1) remove_helper(it);
}

void print_list() {
  for (auto& it : list) cout << "   " << dict1[it] << '\n';
}

int main() {
  string line, cmd, target;
  while (true) {
    getline(cin, line);
    cout << line << '\n';
    istringstream iss(line);
    iss >> cmd;
    switch (cmd[0]) {
      case 'E':
        return 0;
      case 'D':
        depend(iss);
        break;
      case 'I':
        iss >> target;
        install(target);
        break;
      case 'R':
        iss >> target;
        remove(target);
        break;
      case 'L':
        print_list();
        break;
    }
  }
  return 0;
}
This post is licensed under CC BY 4.0 by the author.