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 configuration 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, components 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.
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 DEPENDcommands 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 Syntax | Interpretation/Response |
DEPEND item1 item2 [item3 ...] | item1 depends on item2 (and item3 ...) |
INSTALL item1 | install item1 and those on which it depends |
REMOVE item1 | remove item1, and those on which it depends, if possible |
LIST | list the names of all currently-installed components |
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.
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
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
DEPEND A B INSTALL A INSTALL B REMOVE A END
DEPEND A B INSTALL A Installing B Installing A INSTALL B B is already installed. REMOVE A Removing A Removing B END
前话:虽然划归到数据结构这一章,但还是一个需要熟练使用STL的模拟题;说实话代码是按照如家大神的思路来的,而且如果不看他的思路的话自己的条理也应该不会这么清晰吧...总之又学到了新的思路。学一点就得记住一点啊。
题意:软件组件之间会有依赖关系,比如你下一个Codeblocks你也得顺带着把编译器给下上。你的任务是模拟安装和卸载软件组件的过程。有以下五种指令,如果指令为“END”则退出程序;若为以下四种指令,则分别作对应操作:
Command Syntax | Interpretation/Response |
DEPEND item1 item2 [item3 ...] | item1 depends on item2 (and item3 ...) |
INSTALL item1 | install item1 and those on which it depends |
REMOVE item1 | remove item1, and those on which it depends, if possible |
LIST | list the names of all currently-installed components |
在INSTALL指令中提到的组件成为显示安装,这些组件必须用REMOVE指令显示删除。同样,被显示安装的组件直接或间接依赖的其他组件也不能在REMOVE指令中删除。
最后就是注意字符串输入与输出的细节问题。
分析:
①输入问题:
注意输入的语句需要同一格式输出,所以需要用getline输入,对于语句中会出现空白符且需要提取子串,这里可以用到istringstream类(头文件sstream),其功能为从流中提取数据,支持>>操作,用法为:
1 #include<iostream> 2 #include<sstream> 3 using namespace std; 4 int main() 5 { 6 string str, line; 7 while(getline(cin, line)) 8 { 9 istringstream stream(line); 10 while(stream>>str) 11 cout<<str.c_str()<<endl; 12 } 13 return 0; 14 }
②细节问题:
首先,维护一个组建的名字列表——可以把输入中的组件名全部转化为整数编号。此处可以使用一个map记录出现过的组件名及其编号,使用字符串数组name方便记录编号对应的组件名。
1 int cnt; 2 int ID(string It) 3 { 4 if(item.count(It)) return item[It]; 5 item[It] = ++cnt; 6 name[cnt] = It; 7 return cnt; 8 }
接下来用两个vector数组depend[x]和be_depended[x]分别表示组件x所依赖的组件列表和依赖于x的组件列表。这样就可以方便安装及删除组件。
1 if(com == "DEPEND") 2 { 3 line >> item1; 4 int id1 = ID(item1), id2; 5 while(line >> other) 6 { 7 id2 = ID(other); 8 depend[id1].push_back(id2); 9 be_depended[id2].push_back(id1); 10 } 11 }
为了区别显示安装还是隐式安装,需要一个status[x]数组,0表示组件x未安装,1表示显示安装,2表示隐式安装。
1 void install(int it, bool toplevel) //toplevel区分显、隐示安装 2 { 3 if(!status[it]) //status[x] = 0,组件x未安装 4 { 5 for(int i = 0; i < depend[it].size(); i++) 6 { 7 install(depend[it][i], false); //所有依赖组件隐式安装,递归调用 8 } 9 cout << " Installing " << name[it] << endl; 10 status[it] = toplevel ? 1 : 2; 11 installed.push_back(it); //把已安装的组件加入到vector数组installed中 12 } 13 }
1 if(com == "INSTALL") 2 { 3 line >> item1; 4 int id = ID(item1); 5 if(status[id]) //若该组件已安装 6 cout << " " << name[id] << " is already installed." << endl; 7 else 8 install(id, true); //显式安装 9 }
而对于删除组件,首先判断组件能否删除,即是否被未删除的组件依赖,若能删除,在删除后再递归删除他所依赖的组件。
1 bool needed(int it) 2 { 3 for(int i = 0; i < be_depended[it].size(); i++) 4 { 5 if(status[be_depended[it][i]]) return true; //组件被未删除组件依赖, 6 } 7 return false; 8 } 9 10 void Remove(int it, bool toplevel) 11 { 12 if((toplevel || status[it] == 2) && !needed(it))//若该组件显式卸载或它是隐身安装的,且不被依赖,则可以卸载 13 { 14 status[it] = 0; 15 installed.erase( remove(installed.begin(), installed.end(), it), installed.end() ); //注意erase与remove结合的用法 16 cout << " Removing " << name[it] << endl; 17 for(int i = 0; i < depend[it].size(); i++) 18 { 19 Remove(depend[it][i], false); 20 } 21 } 22 }
剩下的就是小意思了,LIST指令直接按编号输出name[]元素就好;
AC代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<vector> 6 #include<string> 7 #include<map> 8 #include<set> 9 #include<algorithm> 10 #include<cctype> 11 #include<sstream> 12 using namespace std; 13 14 const int maxn = 10000010; 15 vector<int> depend[maxn], be_depended[maxn]; 16 vector<int> installed; 17 map<string, int> item; 18 string name[maxn]; 19 int status[maxn]; 20 int cnt; 21 int ID(string It) 22 { 23 if(item.count(It)) return item[It]; 24 item[It] = ++cnt; 25 name[cnt] = It; 26 return cnt; 27 } 28 29 void install(int it, bool toplevel) 30 { 31 if(!status[it]) //status[x] = 0,组件x未安装;status[x] = 1,显示安装;status[x] = 2,隐式安装; 32 { 33 for(int i = 0; i < depend[it].size(); i++) 34 { 35 install(depend[it][i], false); //隐式安装 36 } 37 cout << " Installing " << name[it] << endl; 38 status[it] = toplevel ? 1 : 2; 39 installed.push_back(it); 40 } 41 } 42 43 bool needed(int it) 44 { 45 for(int i = 0; i < be_depended[it].size(); i++) 46 { 47 if(status[be_depended[it][i]]) return true; //组件被其他组件依赖, 48 } 49 return false; 50 } 51 52 void Remove(int it, bool toplevel) 53 { 54 if((toplevel || status[it] == 2) && !needed(it)) 55 { 56 status[it] = 0; 57 installed.erase( remove(installed.begin(), installed.end(), it), installed.end() ); ///!! 58 cout << " Removing " << name[it] << endl; 59 for(int i = 0; i < depend[it].size(); i++) 60 { 61 // cout << name[depend[it][i]] << endl; 62 Remove(depend[it][i], false); 63 } 64 } 65 } 66 67 int main() 68 { 69 //freopen("in.txt", "r", stdin); 70 cnt = 0; 71 string com, item1, other; 72 getline(cin, com); 73 while(1) 74 { 75 cout << com << endl; 76 istringstream line(com); 77 line >> com; 78 //cout << com << endl; 79 if(com == "END") break; 80 if(com == "DEPEND") 81 { 82 line >> item1; 83 int id1 = ID(item1), id2; 84 while(line >> other) 85 { 86 id2 = ID(other); 87 depend[id1].push_back(id2); 88 be_depended[id2].push_back(id1); 89 } 90 } 91 else if(com == "INSTALL") 92 { 93 line >> item1; 94 int id = ID(item1); 95 if(status[id]) 96 cout << " " << name[id] << " is already installed." << endl; 97 else 98 install(id, true); //显式安装 99 } 100 else if(com == "REMOVE") 101 { 102 line >> item1; 103 int id = ID(item1); 104 if(!status[id]) 105 cout << " " << name[id] << " is not installed." << endl; 106 else if(needed(ID(item1))) 107 cout << " " << name[id] << " is still needed." << endl; 108 else 109 Remove(id, true); //显式卸载 110 } 111 else if(com == "LIST") 112 { 113 for(int i = 0; i < installed.size(); i++) 114 cout << " " << name[installed[i]] << endl; 115 } 116 getline(cin, com); 117 } 118 return 0; 119 }