拓扑排序

校园网主干是由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);

	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值