天天看点

I. Improve SPAM【BFS+拓扑排序】

I. Improve SPAM

题意: 给你一个有向图,N个点中有1-L个为发送点,剩下的为接收点。点1发送一封邮件给他相邻的点,其他的点接着发送,可能会收到多封邮件,每封发送。问接收点一共接收到了多少封邮件,以及多少个接收点收到了邮件。

题解: 换个说法就是说,除了前L个点为发送点其余均为接受点,问从点1出发能够达到多少个接受点并且一共有多少条路径。

  比赛时Sstee1XD直接用了BFS,中间加了一些优化,的确是最出来了。但是后续补题,我还是再写了一遍,加了一个拓扑排序的模板,跑的更快了。

思路: 因为不是所有的接受点都与1点连通,所以直接套拓扑排序是不可行的。需要从一点出发跑一遍BFS,将能够到达的点度数加一(拓扑需要)。结束之后只要一个标准的拓扑模板就能做。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
inline int read(){
   int s = 0, w = 1;
   char ch = getchar();
   while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
   while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
   return s * w;
}
 
const int  N = 2e3 + 10;
const int mod = 1e9 + 7;
int n, m, deg[N];
set<int> S;
vector<int> V[N];
 
void topu(){
	ll ans = 0;
	ll num[N] = {0, 1};
	queue<int> Q;	Q.push(1);
	while(!Q.empty()){
		int u = Q.front(); Q.pop();
		if(u > m){
			ans += num[u];
			if(ans >= mod)	ans -= mod;
			S.insert(u);
		}
		for(auto v : V[u]){
			deg[v]--;
			num[v] += num[u];
			if(num[v] >= mod)	num[v] -= mod;
			if(!deg[v])	Q.push(v);
		}
	}
	printf("%lld %d", ans, S.size());
}
 
void BFS(){
	queue<int> Q;	Q.push(1);
	int vis[N] = {0, 1};
	while(!Q.empty()){
		int u = Q.front(); Q.pop();
		for(auto v : V[u]){
			deg[v]++;
			if(!vis[v])	Q.push(v);
			vis[v] = 1;
		}
	}
}
 
int main(){
	n = read(), m = read();
	for(int i = 1; i <= m; i++){
		int t = read();
		for(int j = 1; j <= t; j++){
			int v = read();
			V[i].push_back(v);
		}
	}
	BFS();
	topu();
	return 0;
}
           

继续阅读