时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

Professor Q develops a new software. The software consists of N modules which are numbered from 1 to N. The i-th module will be started up by signal Si. If signal Si is generated multiple times, the i-th module will also be started multiple times. Two different modules may be started up by the same signal. During its lifecircle, the i-th module will generate Ki signals: E1, E2, ..., EKi. These signals may start up other modules and so on. Fortunately the software is so carefully designed that there is no loop in the starting chain of modules, which means eventually all the modules will be stoped. Professor Q generates some initial signals and want to know how many times each module is started.

输入

The first line contains an integer T, the number of test cases. T test cases follows.

For each test case, the first line contains contains two numbers N and M, indicating the number of modules and number of signals that Professor Q generates initially.

The second line contains M integers, indicating the signals that Professor Q generates initially.

Line 3~N + 2, each line describes an module, following the format S, K, E1, E2, ... , EK. S represents the signal that start up this module. K represents the total amount of signals that are generated during the lifecircle of this module. And E1 ... EK are these signals.

For 20% data, all N, M <= 10
For 40% data, all N, M <= 103
For 100% data, all 1 <= T <= 5, N, M <= 105, 0 <= K <= 3, 0 <= S, E <= 105.

Hint: HUGE input in this problem. Fast IO such as scanf and BufferedReader are recommended.

输出

For each test case, output a line with N numbers Ans1, Ans2, ... , AnsN. Ansi is the number of times that the i-th module is started. In case the answers may be too large, output the answers modulo 142857 (the remainder of division by 142857).

样例输入

3
3 2
123 256
123 2 456 256
456 3 666 111 256
256 1 90
3 1
100
100 2 200 200
200 1 300
200 0
5 1
1
1 2 2 3
2 2 3 4
3 2 4 5
4 2 5 6
5 2 6 7
样例输出
1 1 3
1 2 2
1 1 2 3 5
解题思路:这个题目的思路很简单,建立好图之后,DFS扫一遍就ok了。。。但看官方题解,这个算法还不是最优的,最优的是建立的图之后进行拓扑排序。。。仔细想想确实是这样的,只能说观察不够细致。。

解题思路

通过题意,我们首先可以确定,不同模块之间可以按照以下原则构成一个有向无环图:
  • 初始信号流,即 M 个初始信号,我们将其设定为模块0发出的信号
  • 若模块i发出的信号能够使得模块j被激活,我们连接一条从ij的有向边(i,j)
比如数据:
3 2
123 256
123 2 456 256
456 3 666 111 256
256 1 90
对应的图为:由于原题中给出的信号在0~10^5之间,因此我们可以用一个大小为10^5的数组signList来记录信号可以激活的模块,辅助我们构造整个图:
Input n
Input m
// 将初始数据流做为 module 0
For i = 1 .. mInput signmodule[0].sendSign.push(sign)
End For
// 读取其他module的信息
For i = 1 .. nInput signmodule[i].activeSign = signsignList[ sign ].canActiveModule.push(i)Input numFor j = 1 .. numInput signmodule[i]sendSign.push(sign)End For
End For
// 构造有向无环图
For i = 0 .. nFor sign in module[i].sendSignFor j in signList[ sign ].canActiveModuleaddEdge(i, j)End ForEnd For
End For
在得到有向无环图之后,一个简单的做法是直接在上面做一次DFS,去统计每个点被访问到的次数:
DFS(nowModule):If (nowModule not 0) ThenactiveCount[ nowModule ] = activeCount[ nowModule ] + 1End IfFor each j in (nowModule, j)DFS(j)End For
该算法的时间复杂度非常高,但由于本题没有设计专门针对的数据,所以在测试时也能通过所有的测试点。但是显然这不是我们要的最优算法,本题实际考察的算法为拓扑排序(toposort)。利用拓扑排序,在O(n + m)的时间内计算出所有点被访问的次数,具体的算法讲解可以参见hiho一下第48期在本题中,访问次数对应的为第48期题目中的病毒数量。因此我们在构造完图之后,可以使用同样的算法来解决:
// 在构造图时同时统计入度
For i = 0 .. nFor sign in module[i].sendSignFor j in signList[ sign ].canActiveModuleaddEdge(i, j)inDegree[j] = inDegree[j] + 1End ForEnd For
End For// 进行拓扑排序
tail = 0;
For i = 0 .. n  // 这里一定要从0开始,因为Module 0也是图中的点If (inDegree[i] == 0) Then  // 入度为0的点sequence[tail] = itail = tail + 1End If
End ForactiveCount[0] = 1  // 设定初始信号流的访问次数为1
activeCount[1 .. n] = 0
i = 0
While (i < tail) ThennowModule = sequence[i]For each j in (nowModule, j)activeCount[j] = activeCount[j] + activeCount[ nowModule ]inDegree[j] = inDegree[j] - 1If (inDegree[j] == 0) Thensequence[tail] = jtail = tail + 1End IfEnd Fori = i + 1
End While
最后再将activeCount数组依次输出即可。由于本题有多组数据,在实现时一定要注意初始化。
AC:
#include<cstdio>
#include<cstring>
using namespace std;const int maxn = 1e5+5;
struct SOFTWARE
{int start;int num;int E[5];
}sft[maxn];struct VERTEX
{int startE;int first;
}ver[maxn];struct Node
{int id;int next;
}list[maxn];
int n,m,sign[maxn],cnt,vis[maxn];void add(int e,int id)
{ver[e].startE = e;list[cnt].id = id;if(ver[e].first == -1) ver[e].first = cnt++;else{list[cnt].next = ver[e].first;ver[e].first = cnt++;}
}void init()
{memset(vis,0,sizeof(vis));memset(list,-1,sizeof(list));memset(ver,-1,sizeof(ver));cnt = 0;
}void dfs(int cur,int e)
{if(ver[e].first == -1) return;for(int i = ver[e].first; i != -1; i = list[i].next){int k = list[i].id;vis[k]++;for(int j = 1; j <= sft[k].num; j++)dfs(k,sft[k].E[j]);}
}int main()
{   int t;scanf("%d",&t);while(t--){init();scanf("%d%d",&n,&m);for(int i = 1; i <= m; i++)scanf("%d",&sign[i]);for(int i = 1; i <= n; i++){scanf("%d%d",&sft[i].start,&sft[i].num);add(sft[i].start,i);for(int j = 1; j <= sft[i].num; j++)scanf("%d",&sft[i].E[j]);}for(int i = 1; i <= m; i++)dfs(0,sign[i]);for(int i = 1; i <= n; i++)printf("%d ",vis[i]);printf("\n");}return 0;
}

hihocoder #1136 : Professor Q's Software相关推荐

  1. 微软2016校园招聘在线笔试 B Professor Q's Software [ 拓扑图dp ]

    传送门 题目2 : Professor Q's Software 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Professor Q develops a new s ...

  2. 关于添加 HKEY_LOCAL_MACHINE32\Software 注册表问题

    关于添加 HKEY_LOCAL_MACHINE32\Software 注册表问题 Q: HKEY_LOCAL_MACHINE32\Software 这个目录在哪里? A: HKEY_LOCAL_MAC ...

  3. sun服务器Solaris9安装

    sun服务器Solaris9安装 1.开机上电,等待显示器亮后,按Stop-a键.如果是在终端上安装,按Ctrl-Break键. 这时,服务器进入OK监控状态: OK 2.将Solaris9系统盘So ...

  4. Solari8终端安装

                                                           Solari8终端安装  1.开机上电,等待显示器亮后,sun自己的键盘按Stop-a键. ...

  5. [转]window下使用SetUnhandledExceptionFilter捕获让程序的崩溃

    [转]window下使用SetUnhandledExceptionFilter捕获让程序的崩溃 简单使用SetUnhandledExceptionFilter()函数让程序优雅崩溃 虽然是大公司的产品 ...

  6. hihoCoder 网络流四·最小路径覆盖

    题面带解释 hihoCoder感觉很好. 网络流的精华就是建图 #include<cstdio> #include<iostream> #include<algorith ...

  7. hihocoder 后缀自动机专题

    一.后缀自动机基本概念的理解 1.首先后缀自动机的状态是由子串的endpos来决定的 子串的endpos是指一个子串可以在原字符串的哪些位置进行匹配, endpos构成的不同集合划分成不同的状态 关于 ...

  8. hihoCoder 第136周 优化延迟(二分答案+手写堆)

    题目1 : 优化延迟 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho编写了一个处理数据包的程序.程序的输入是一个包含N个数据包的序列.每个数据包根据其重要程度不同 ...

  9. hihoCoder 1578 Visiting Peking University 【贪心】 (ACM-ICPC国际大学生程序设计竞赛北京赛区(2017)网络赛)...

    #1578 : Visiting Peking University 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 Ming is going to travel for ...

最新文章

  1. 在程序中集成地址簿、电子邮件和地图功能
  2. BZOJ 4734 UOJ #269 如何优雅地求和 (多项式)
  3. 糖尿病动物模型知识点整理
  4. Oracle左右链接
  5. 巧用 TypeScript Literal Types 模拟枚举类型
  6. 【转】.so兼容32位和64位
  7. requirejs 定义模块中含有prototype
  8. 带你读论文丨异常检测算法及发展趋势分析
  9. 关于python中自己写的模块之前相互调用函数
  10. 超级楼梯[HDU2041]
  11. hue 用oozie调度shell(sqoop)脚本问题
  12. PHP字符编码绕过漏洞总结
  13. Paint方法总结(三):图层混合模式
  14. 【整理操作】MQTT简单使用学习
  15. 网页内嵌多媒体内容的完美实现
  16. 华为交换机基本配置,秒看秒懂~~~
  17. python实现的好玩的小程序--利用wxpy实现的微信可检测僵尸粉机器人
  18. 重温数据结构与算法之单调栈
  19. git推送拉取需要验证信息
  20. android 短信打开APP

热门文章

  1. PAT A1023 sort cmp字典序比较
  2. Python爬虫学习笔记(三)——正则表达式
  3. 【spring boot】spring boot @ConditionalOnxxx相关注解总结
  4. leetcode307. Range Sum Query - Mutable
  5. Scala 语言之模式匹配(6)
  6. 标准缺失成发展阻碍 智能家居普及之路任重而道远
  7. 深入浅出Netty之四 Client请求处理
  8. 人和计算机在时间管理方面的相似性
  9. invester is the person whose opinion is so valuable
  10. reciprocity