SmartSoftware Installer
Time Limit: 2000/1000 MS(Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 288 Accepted Submission(s): 94
Problem Description
The softwareinstallation is becoming more and more complex. An automatic tool is oftenuseful to manage this process. An IT company is developing a system managementutility to install a set of software packages automatically with thedependencies. They found that reboot is often required to take effect afterinstalling some software. A software package cannot be installed until allsoftware packages it depends on are installed and take effect.
In the beginning, they implemented a simple installation algorithm, but thesystem would reboot many times during the installation process. This will havea great impact on the user experience. After some study, they think that thisprocess can be further optimized by means of installing as much packages aspossible before each reboot.
Now, could you please design and implement this algorithm for them to minimizethe number of restart during the entire installation process?
Input
The first line isan integer n (1 <= n <= 100), which is the number of test cases. Thesecond line is blank. The input of two test cases is separated by a blank line.
Each test case contains m (1 <= n <= 1000) continuous lines and each lineis no longer than 1024 characters. Each line starts with a package name and acomma (:). If an asterisk (*) exists between the package name and the comma,the reboot operation is required for this package. The remaining line is theother package names it depends on, separated by whitespace. Empty means thatthere is no dependency for this software. For example, “a: b” means package bis required to be installed before package a. Package names consist of letters,digits and underscores, excluding other special symbols.
Assume all packages here need to be installed and all referenced packages willbe listed in an individual line to define the reboot property. It should benoted that cyclic dependencies are not allowed in this problem.
Output
For each testcase, you should output a line starting with “Case #: " (# is the No. ofthe test case, starting from 1) and containing the reboot count for this testcase. (Refer to the sample format)
Sample Input
2
glibc:
gcc*: glibc
uefi*:
gcc*:
raid_util*: uefi
gpu_driver*: uefi
opencl_sdk: gpu_drivergcc
Sample Output
Case 1: 1
Case 2: 2
题目意思:有一批软件需要安装,“:”前的软件需要在“:”后的软件安装完成后才能安装(“:”后面可能有多个软件),“*”表明该软件需要重启才完成安装。
求所有软件都完成安装最少重启的次数。
解题思路:
双队列top排序,用两个队列q1,q2分别来存不需要重启的软件和需要重启的软件。首先将入度的0的点加进队列,当然不需要重启的进q1,需要重启的进q2。然后删除q1中的所有节点,让与他们相连的节点的入度减1,如果发现减完入度为0,再判断其是否需要重启,并加进q1 or q2。一旦发现q1为空,那么使答案加1(即重启一次),把q2中所有元素加入q1,q2清空。如此循环直到q1,q2均为空即可。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<cmath>
#define INF 0xfffffff
#define MAX 1000000
#define CLR(a,b) memset((a),(b),sizeof((a)))
using namespace std;
typedef long long ll;
int edge[2005][2005];
int vis[2005];
int degree[2005];
int tot,ans;
map<string,int> mp;
queue<int>q1,q2;
void top_sort() {
for(int i=1; i<=tot; i++)
if(!degree[i]) {
if(!vis[i])
q1.push(i);
else q2.push(i);
}
while(!q1.empty()||!q2.empty()) {
if(q1.empty()&&!q2.empty()) {
ans++;
while(!q2.empty()) {
int x=q2.front();
q2.pop();
q1.push(x);
}
}
while(!q1.empty()) {
int x=q1.front();
q1.pop();
for(int i=1; i<=tot; i++)
if(edge[i][x]) {
degree[i]--;
if(!degree[i]) {
if(!vis[i])
q1.push(i);
else q2.push(i);
}
}
}
}
}
void init() {
CLR(degree,0);
CLR(edge,0);
CLR(vis,0);
tot=0;
ans=0;
mp.clear();
while(!q1.empty()) q1.pop();
while(!q2.empty()) q2.pop();
}
string p,last[1005];
int main() {
int a,b;
int t;
string s;
scanf("%d",&t);
getchar();
getchar();
for(int cas=1; cas<=t; cas++) {
init();
while(getline(cin,s)!=NULL) {
if(s[0] == '\0')
break;
int len=s.size();
int flag=0; ///用于标记是否需要重启
int havelast=0; ///用于标记是否有安装的前提
p="";
int lastnum=-1; ///需要先安装的个数
for(int i=0; i<len; i++) {
if(s[i]==' ') {
last[++lastnum]="";
continue;
}
if(s[i]=='*') {
flag=1;
continue;
}
if(s[i]==':') {
havelast=1;
continue;
}
if(havelast==0) p+=s[i];
else last[lastnum]+=s[i];
}
if(mp.find(p)==mp.end()) mp[p]=++tot; ///发现新的软件名 并编号 便于建图
vis[mp[p]]=flag;
int m=0;
while(last[m].size()>0&&m<=lastnum) {
if(mp.find(last[m])==mp.end()) mp[last[m]]=++tot;
edge[mp[p]][mp[last[m]]]=1; ///建边
m++;
}
}
for(int i=1; i<=tot; i++)
for(int j=1; j<=tot; j++)
if(edge[i][j]) degree[i]++;
top_sort();
cout<<"Case "<<cas<<": "<<ans<<endl;
}
}