校园网主干是由N个节点(编号1…N)组成,这些节点之间有一些单向的网路连接。若存在一条网路连接(u,v)链接了节点u和节点v,则节点u可以向节点v发送信息,但是节点v不能通过该链接向节点u发送信息。
在刚感染病毒时,校园网立刻切断了一些网络链接,恰好使得剩下网络连接不存在环,避免了节点被反复感染。也就是说从节点i扩散出的病毒,一定不会再回到节点i。
当1个病毒感染了节点后,它并不会检查这个节点是否被感染,而是直接将自身的拷贝向所有邻居节点发送,它自身则会留在当前节点。所以一个节点有可能存在多个病毒。
现在已经知道黑客在一开始在K个节点上分别投放了一个病毒。
输入
第1行:3个整数N,M,K,1≤K≤N≤100,000,1≤M≤500,000
第2行:K个整数A[i],A[i]表示黑客在节点A[i]上放了1个病毒。1≤A[i]≤N
第3…M+2行:每行2个整数 u,v,表示存在一条从节点u到节点v的网络链接。数据保证为无环图。1≤u,v≤N
输出
第1行:1个整数,表示最后整个网络的病毒数量 MOD 142857
解题思路:这是一个比较典型的拓扑排序问题,而拓扑排序一般是建立邻接表来进行操作,我的邻接表的建立是用一个数组作为顶点表,以链表建立邻接点(因为题目的数据范围太大,以数组建立邻接点程序会爆,当然,邻接表的建立可以用不同的方法,不一定非要我的这种,仁者见仁智者见智)
易错点:注意病毒的数量,我是每出现一次与病毒数量相关的数据我就MOD 142857;
因为写的仓促,我的代码有些冗余
#include<stdio.h>
#include<string.h>
struct zi
{
int adj;
struct zi*next;
};
struct ve
{
int in;
int virus;
struct zi*firstedge;
struct zi*end;
}head[100001];
int main()
{
int n, m,spot;
while (~scanf("%d%d%d", &n, &m,&spot))
{
int count = 0,sum=0;
memset(head, 0, sizeof(head));
int i, j;
for (i = 0; i < spot; i++)
{
int subscript;
scanf("%d", &subscript);
head[subscript].virus +=1;
}
for (i = 0; i < m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
struct zi *pnew = (struct zi*)malloc(sizeof(struct zi));
pnew->next = NULL;
pnew->adj = v;
head[v].in++;
if (head[u].firstedge == NULL)
head[u].firstedge = pnew;
else
head[u].end->next = pnew;
head[u].end = pnew;
pnew = NULL;
}
int stack[100001];
int top = 0;
for (i = 1; i <= n; i++)
{
if (head[i].in == 0)
stack[++top] = i;
}
while (top != 0)
{
int g = stack[top--];
count++;
sum += head[g].virus% 142857;
sum =sum % 142857;
for (struct zi*e = head[g].firstedge; e != NULL; e = e->next)
{
int k = e->adj;
head[k].virus = head[k].virus% 142857 + head[g].virus% 142857;
if (!(--head[k].in))
stack[++top] = k;
}
}
printf("%d\n", sum);
}
}