Professor Q's Software——邻接表实现拓扑排序

来源:互联网 发布:diag矩阵的逆矩阵 编辑:程序博客网 时间:2024/06/05 03:40

昨天参加了微软的笔试,雷雨交加,心惊胆战……

废话不多说,来看一下题目吧:


时间限制: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).


样例输入
33 2123 256123 2 456 256456 3 666 111 256256 1 903 1100100 2 200 200200 1 300200 05 111 2 2 32 2 3 43 2 4 54 2 5 65 2 6 7
样例输出
1 1 31 2 21 1 2 3 5


题目翻译:

有n个模块,每个模块有一定的信号频率,如果接受到了,它就会工作,然后会发送多种信号频率。先已知发出的一些信号,求每个模块工作的次数。

输入

案例数T

模块数N  初始信号数M

初始信号Q1....Qm

激发该模块的信号S   该模块发出的信号数K   该模块发出的信号E1...Ek

输出

每个案例中每个模块工作的次数(模142857后再输出


解题思路

使用拓扑排序计算每个模块的工作次数。将模块当做点,若A能激发B,则有一条A指向B的边。

用一个数组来保存每个顶点的度(入度),即可以激发这个模块工作的信号数。

用vector与数组结合来实现邻接表,表示模块间的相互激发关系。

用队列实现拓扑排序。

1. 找到入度为0的点,将他们入队;

2.对于每个入度为0的点,在邻接表中找到它指向的点,即找到它可以激发的模块i;

   模块i工作次数=模块i被初始信号激发的次数+模块i被入度为零的点激发的次数;

3.模块i的入度减一,如果此时模块i的入度为0(所有可激发模块i的点都已经被用于计算模块i的工作次数,模块i的工作次数计算完        毕),代表模块i的点入队,用于计算模块i所能激发的模块的工作次数;

4.以此类推,一直到所有点的入度为零。


#include<cstdio>#include<iostream>#include<cstring>#include<map>#include<vector>#include<queue>using namespace std;const int maxn = 1001000;int n , m , S , K , Q , E , du[maxn] , ans[maxn] , module[maxn];//du为度,可激发该模块的信号数; ans为模块工作的次数; module为模块对应的信号编号vector < int > graph[maxn]; //邻接表,相当于graph[模块编号][该模块可发出的信号编号]map < int , int > Hash; //键值:信号编号;映射值:模块号int main() {    int cast;    for ( cin >> cast; cast; cast -- ) {        scanf("%d%d",&n,&m);//模块数,教授发出的初始信号数        Hash.clear();        int num = 0;        for ( int i = 0; i < 4 * n; i ++ ) {//初始化            du[i] = ans[i] = 0;            graph[i].clear();        }        for ( int i = 0; i < m; i ++ ) {            scanf("%d",&Q); //教授发出的初始信号            if ( !Hash.count(Q) ) //如果map中不存在Q这个键值                Hash[Q] = num ++;            ans[Hash[Q]] ++; //初始信号发出后,对应的模块工作一次        }        for ( int i = 0; i < n; i ++ ) {            scanf("%d%d",&S,&K); //激发该模块的信号,该模块发出的信号数            if ( !Hash.count(S) )                Hash[S] = num ++;            S = Hash[S];            module[i] = S;            for ( int j = 0; j < K; j ++ ) {                scanf("%d",&E);                if ( !Hash.count(E) )                    Hash[E] = num ++;                E = Hash[E];                graph[S].push_back( E );//将S模块可发出的信号存入动态数组                du[E] ++;//信号E被发出的次数增加            }        }        queue < int > q;        for ( int i = 0; i < num ; i ++ ) if ( du[i] == 0 )            q.push( i );        while ( !q.empty() ) {            int top = q.front();            q.pop();            for ( int i = graph[top].size() - 1 ; i >= 0; i -- ) {                int nex = graph[top][i];                ( ans[nex] += ans[top] ) %= 142857; //工作次数=初始信号激发次数+其他模块发出的信号激发次数(其他模块的工作次数)                du[nex] --; //nex的入度减一,即激发nex工作的模块数减一                if ( du[nex] == 0 )                    q.push( nex ); //此时nex的工作次数已算完,入队,计算nex可激发的其他模块的工作次数            }        }        for ( int i = 0; i < n; i ++ )            printf("%d%c",ans[module[i]],i<n-1?' ':'\n');    }    return 0;}


0 0
原创粉丝点击