"尚学堂杯"哈尔滨理工大学第七届程序设计竞赛 D.Distinct Package Manager【Dfs+模拟】

75 篇文章 0 订阅

Distinct Package Manager
Time Limit: 1000 MSMemory Limit: 512000 K
Total Submit: 31(11 users)Total Accepted: 10(6 users)Rating: Special Judge: No
Description

On Linux or OSX, we can install software by package manager. For example, apt-get in Ubuntu/Debian, yum in Fedora/CentOS and brew in OSX. All of them are great software-package manager.

You determined to design your own software-package manager. The inevitable thing is you should solve dependences of these software-packages.

    • If package A depends package B, you should install package B before installing package A. 

    • If you want to uninstall package B, then you must uninstall package A.

Now, you already know all the dependences of all these software-packages. You can assume that 0-package don’t depend any other package. And all dependence-relationship won’t form a circle. Of course, no package depend itself.

Your uses want to know how many packages’ install state will be changed when installing or uninstalling a package.

NOTE: Install an installed package and uninstall an uninstalled package won’t change any packages’ state.


Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases.

The first line of each test cases contains an integer n(1<=n<=100), indicating the number of software-packages.

For each software-package(except 0-package) contains two lines, the first line contains an integer mi, indicating the number of dependences of i-package. The next mi integers indicating the serial numbers of dependences.

The next line contains an integer q(1<=q<=200), indicating the number of queries.

Each of the next q liens contains a string s and an integer k, indicating the action and serial number of software-package. s must be one of "install" and "uninstall".

Output
For each query, output a line contains the number of changed packages.
Sample Output
1
2
1
0
2
install 1
uninstall 0
Hint
2
2
Source
"尚学堂杯"哈尔滨理工大学第七届程序设计竞赛

题目大意:

给你N个软件,0号软件是基础软件,有1~N-1个其他软件,0号软件是可以直接安装的,其他软件要依赖于其他软件,如果a依赖于b,那么b一定要在a之前安装。

相反,在卸载的时候要先卸载b再卸载a.

其中有q个查询,安装或卸载一个软件需要多少次操作。


思路:


1、重要的话说一万遍(就是因为这个0号软件的误导,让我默认为这个点是一个超级源点,然后就和冠军失之交臂......):

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;

这个图,不保证一定连通;


2、sb题,直接模拟即可。

先预处理出来can【i】【j】表示从点i能够有路能够通向j.

然后对于每个查询,过程维护一下即可。


Ac代码:


#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
int can[160][160];
int rcan[160][160];
int zhuangtai[160];
int vis[160];
int ans;
vector<int >mp[1040];
vector<int >rmp[1040];
void Dfs_can(int u,int root)
{
    can[root][u]=1;
    vis[u]=1;
    for(int i=0;i<mp[u].size();i++)
    {
        int v=mp[u][i];
        if(vis[v]==0)
        {
            Dfs_can(v,root);
        }
    }
}
void rDfs_can(int u,int root)
{
    rcan[root][u]=1;
    vis[u]=1;
    for(int i=0;i<rmp[u].size();i++)
    {
        int v=rmp[u][i];
        if(vis[v]==0)
        {
            rDfs_can(v,root);
        }
    }
}
void Dfs(int u,int target)
{
    vis[u]=1;
    if(zhuangtai[u]==0)
    {
        zhuangtai[u]=1;
        ans++;
    }
    for(int i=0;i<mp[u].size();i++)
    {
        int v=mp[u][i];
        if(vis[v]==0&&can[v][target]==1)
        {
            Dfs(v,target);
        }
    }
}
void rDfs(int u,int target)
{
    vis[u]=1;
    if(zhuangtai[u]==1)
    {
        zhuangtai[u]=0;
        ans++;
    }
    for(int i=0;i<rmp[u].size();i++)
    {
        int v=rmp[u][i];
        if(vis[v]==0&&rcan[v][target]==1)
        {
            rDfs(v,target);
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        memset(zhuangtai,0,sizeof(zhuangtai));
        memset(can,0,sizeof(can));
        memset(rcan,0,sizeof(rcan));
        for(int i=0;i<=n+5;i++)mp[i].clear();
        for(int i=0;i<=n+5;i++)rmp[i].clear();
        for(int i=1;i<n;i++)
        {
            int mi;
            scanf("%d",&mi);
            int flag=0;
            for(int j=0;j<mi;j++)
            {
                int u;
                scanf("%d",&u);
                if(u==0)flag=1;
                mp[u].push_back(i);
                rmp[i].push_back(u);
            }
        }
        for(int i=0;i<n;i++)memset(vis,0,sizeof(vis)),Dfs_can(i,i);
        for(int i=0;i<n;i++)memset(vis,0,sizeof(vis)),rDfs_can(i,i);
        int q;
        scanf("%d",&q);
        while(q--)
        {
            char op[100];
            int num;
            scanf("%s%d",op,&num);
            if(strcmp(op,"install")==0)
            {
                if(zhuangtai[num]==1)
                {
                    printf("0\n");
                    continue;
                }
                ans=0;
                memset(vis,0,sizeof(vis));
                for(int i=0;i<n;i++)
                {
                    if(vis[i]==0&&can[i][num]==1)
                    {
                        Dfs(i,num);
                    }
                }
                printf("%d\n",ans);
            }
            else
            {
                if(zhuangtai[num]==0)
                {
                    printf("0\n");
                    continue;
                }
                ans=0;
                memset(vis,0,sizeof(vis));
                for(int i=0;i<n;i++)
                {
                    if(vis[i]==0&&rcan[i][num]==1)
                    {
                        rDfs(i,num);
                    }
                }
                printf("%d\n",ans);
            }
        }
    }
}










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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值