题意:要安装一些软件,有些软件安装完就能生效,有些需要重启。有些软件甚至要需要其它一些软件生效的情况下才能安装。
要求安装完所有软件并且全部生效的最少重启次数。
对于需要重启的软件,在它的名字后面跟着个*,冒号后面表示它所依赖的软件名称。
我们可以根据依赖关系构建有向图,比如A依赖B的话,就构造B->A,题目保证不存在环。
那么我们就可以保存好入度,用一个队列表示当前可以安装的软件;
一开始将入度为0的放进队列,逐个拿出来安装,如果需要重启,先保存起来,不需要重启的就将它指向的点全部入度减1,遇到入度变成0的就加入队列。
当队列为空时,就把那些需要重启的全部重启一下,其实就是扩展一遍,这样队列可能就会有新的软件可以安装。
这样直到全部安装完生效就可以了。
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<queue>
#include<vector>
#include<stack>
using namespace std;
map<string,int> MP;
stack<int> ST;
const int N = 1100;
char ss[N], s[N];
int T, t, m, in[N];
bool mk[N];
vector<int> V[N];
int getid(){
if(!MP.count(s)){
MP[s] = ++m;
V[m].clear();
}
return MP[s];
}
void solve(){
int ans = 0, cnt = m;
queue<int> Q;
for(int i=1; i<=m; i++){
if(!in[i]) Q.push(i);
}
while(cnt){
while(!Q.empty()){
int x=Q.front(); Q.pop();
if(mk[x]) ST.push(x);
else{
cnt--;
for(int i=0; i<V[x].size(); i++){
int j = V[x][i];
if(!(--in[j])) Q.push(j);
}
}
}
if(!cnt) break;
ans++;
while(!ST.empty()){
int x = ST.top(); ST.pop();
cnt--;
for(int i=0; i<V[x].size(); i++){
int j = V[x][i];
if(!(--in[j])) Q.push(j);
}
}
}
printf("Case %d: %d\n", ++t, ans);
}
void init(){
MP.clear();
m = 0;
memset(mk, 0, sizeof(mk));
memset(in, 0, sizeof(in));
}
void insert(){
int len = strlen(ss);
bool flag = 0;
int i, j;
for(i=0; i<len; i++){
if(ss[i]=='*'){
flag = 1;
s[i] = '\0';
break;
}
if(ss[i]==':'){
s[i] = '\0';
break;
}
s[i] = ss[i];
}
int x = getid();
mk[x] |= flag;
for(i+=2, j=0; i<len; i++){
if(ss[i]==' '){
s[j] = '\0';
int y = getid();
V[y].push_back(x);
in[x]++;
j = 0;
}
else{
s[j++] = ss[i];
}
}
s[j] = '\0';
int y = getid();
V[y].push_back(x);
in[x]++;
}
int main(){
scanf("%d", &T);
getchar();
gets(ss);
t = 0;
init();
while(gets(ss)){
if(strcmp(ss, "")==0){
solve();
init();
}
else{
insert();
}
}
solve();
return 0;
}