hdu 5098 拓扑排序

Smart Software Installer

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 208 Accepted Submission(s): 59


Problem Description
The software installation is becoming more and more complex. An automatic tool is often useful to manage this process. An IT company is developing a system management utility to install a set of software packages automatically with the dependencies. They found that reboot is often required to take effect after installing some software. A software package cannot be installed until all software packages it depends on are installed and take effect.

In the beginning, they implemented a simple installation algorithm, but the system would reboot many times during the installation process. This will have a great impact on the user experience. After some study, they think that this process can be further optimized by means of installing as much packages as possible before each reboot.

Now, could you please design and implement this algorithm for them to minimize the number of restart during the entire installation process?

Input
The first line is an integer n (1 <= n <= 100), which is the number of test cases. The second 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 line is no longer than 1024 characters. Each line starts with a package name and a comma (:). If an asterisk (*) exists between the package name and the comma, the reboot operation is required for this package. The remaining line is the other package names it depends on, separated by whitespace. Empty means that there is no dependency for this software. For example, “a: b” means package b is 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 will be listed in an individual line to define the reboot property. It should be noted that cyclic dependencies are not allowed in this problem.

Output
For each test case, you should output a line starting with “Case #: " (# is the No. of the test case, starting from 1) and containing the reboot count for this test case. (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

Source
普通的拓扑排序用了一个队列,而现在用两个队列q1,q2分别来存 不需要重启的software 和 需要重启的software。根据题目输入建好图后,按照拓扑序规则,首先将入度的0的点加进队列,当然不需要重启的进q1,需要的进q2。然后处理q1中的所有节点(即要删除这些点),那么要让与他们相连的节点的入度减1,如果发现减完入度为0,再判断其是否需要重启,并加进q1 or q2。一旦发现q1为空,再判断q2,q2不为空的话 那么使答案加1(即重启一次),然后交换q1和q2 。如此循环直到q1,q2均为空即可。
注意输入,比较蛋疼。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<map>
#include<string>
#include<sstream>
#include<queue>
#include<vector>
#define N 2000
using namespace std;
int vis[N],degree[N],e,head[N];
map<string,int>ma;
struct node
{
    int u,v,next;
}bian[N*2];
char str[N];
void add(int u,int v)
{
    bian[e].u=u;
    bian[e].v=v;
    bian[e].next=head[u];
    head[u]=e++;
}
int topsort(int num)
{
    queue<int> q[2];
    int a=0,b=1,i;
    for(int i=1;i<num;i++)
    {
        if(degree[i]==0)
        {
            if(vis[i]==1) q[b].push(i);
            else q[a].push(i);
        }
    }
    int time=0;
    while(!q[a].empty()||!q[b].empty())
    {
        while(!q[a].empty())
        {
            int u=q[a].front(); q[a].pop();
            for(i=head[u];i!=-1;i=bian[i].next)
            {
                int v=bian[i].v;
                degree[v]--;
                if(degree[v]==0)
                {
                    if(vis[v]==1) q[b].push(v);
                    else q[a].push(v);
                }
            }
        }
        if(q[b].empty()==true) continue;
        time++;swap(a,b);
    }
    return time;
}
int main()
{
    int t,num,i,u,k,ans,j,cnt=1;
    char s[1025];
    scanf("%d",&t);
    getchar();getchar();//特殊处理开头
    while(t--)
    {
        num=1;
        ma.clear();e=0;
        memset(head,-1,sizeof(head));
        memset(degree,0,sizeof(degree));
        memset(vis,0,sizeof(vis));
        while(gets(str))
        {
            if(strcmp(str,"")==0)
                break;//遇见空行结束
           int n=strlen(str);
            for(i=0;i<n;i++)
            {
                if(str[i]=='*')
                {
                    str[i]='\0';
                    if(ma[str]==0)
                        ma[str]=num++;
                  vis[ma[str]]=1;
                  i+=3;  u=ma[str];
                  break;
                }
                else if(str[i]==':')
                {
                    str[i]='\0';
                    if(ma[str]==0)
                        ma[str]=num++;
                    i+=2; u=ma[str];
                    break;
                }
            }
               k=0;
               for(j=i;j<n;j++)
               {
                   if(str[j]==' ')
                   {
                    s[k]='\0';
                    if(ma[s]==0)
                        ma[s]=num++;
                    degree[u]++;
                    add(ma[s],u);//用邻接表存边,用容器存,一直运行错误
                    k=0;
                   }
                   else
                    s[k++]=str[j];
                }
                if(k!=0)
                {//注意添加最后一个
                     s[k]='\0';
                    if(ma[s]==0)
                        ma[s]=num++;
                    degree[u]++;
                    add(ma[s],u);
                }
        }
      ans=topsort(num);
      printf("Case %d: %d\n",cnt++,ans);
    }
    return 0;
}

参考别人写的:学习一下输入。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <string>
#include <sstream>
#include <map>
#include<vector>
#include <queue>
using namespace std;
const int maxn=2000;
map<string,int> ms;
int nm;
bool vis[maxn];
int degree[maxn],e,head[maxn];
struct node
{
    int u,v,next;
}bian[maxn*2];
int hash(string name)
{
    int ret=ms[name];
    if(ret==0)
    {
        ms[name]=nm++;
        ret=nm-1;
    }
    return ret;
}
void add(int u,int v)
{
    bian[e].u=u;
    bian[e].v=v;
    bian[e].next=head[u];
    head[u]=e++;
}
int topsort()
{
    queue<int> q[2];
    int a=0,b=1,i;
    for(int i=1;i<nm;i++)
    {
        if(degree[i]==0)
        {
            if(vis[i]==true) q[b].push(i);
            else q[a].push(i);
        }
    }
    int time=0;
    while(!q[a].empty()||!q[b].empty())
    {
        while(!q[a].empty())
        {
            int u=q[a].front(); q[a].pop();
            for(i=head[u];i!=-1;i=bian[i].next)
            {
                int v=bian[i].v;
                degree[v]--;
                if(degree[v]==0)
                {
                    if(vis[v]==true) q[b].push(v);
                    else q[a].push(v);
                }
            }
        }
        if(q[b].empty()==true) continue;
        time++;swap(a,b);
    }
    return time;
}
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    getchar(); getchar();
    while(T--)
    {
        ms.clear(); nm=1; e=0;
        memset(head,-1,sizeof(head));
        memset(vis,false,sizeof(vis));
        memset(degree,0,sizeof(degree));
        string line,name;
        while(getline(cin,line))
        {//getline()是定义在<string>中的一个行数,用于输入一行string,以enter结束。
            if(line[0]==0) break;
            istringstream sin(line);
            sin>>name;//istringstream对象可以绑定一行字符串,然后以空格为分隔符把该行分隔开来。
            bool flag=false;
            int sz=name.size();
            if(name[sz-2]=='*')
            {
                flag=true;
                name[sz-2]=0;
                name.resize(sz-2);//截取前多少个字符
            }
            else
            {
                name[sz-1]=0;
                name.resize(sz-1);
            }
            int to=hash(name);
            vis[to]=flag;
            while(sin>>name)
            {
                int from=hash(name);
                add(from,to);
                degree[to]++;
            }
        }
        printf("Case %d: %d\n",cas++,topsort());
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值