1076 Forwards on Weibo (30 分)
题意
在微博中,每个用户都可能被若千个其他用户关注。而当该用户发布一条信息时,他的关注者就可以看到这条信息并选择是否转发它,且转发的信息也可以被转发者的关注者再次转发,但同一用户最多只转发该信息一次(信息的最初发布者不会转发该信息)。现在给出N个用户的关注情况( 即他们各自关注了哪些用户)以及一个转发层数上限L,并给出最初发布消息的用户编号,求在转发层数上限内消息最多会被多少?
思路
- 首先考虑如何建图。由于题目给定的数据是用户关注的情况(而不是被关注的情况),因此如果用户X关注了用户Y,则需要建立由Y指向X的有向边,来表示Y发布的消息可以传递到X并被X转发。
- 在建图完毕后,使用DFS或者BFS都可以得到需要的结果。如果使用DFS来遍历,只要控制遍历深度不超过题目给定的层数L即可,遍历过程中计数访问到的结点个数(细节处理会比较麻烦)。如果使用BFS来遍历,则需要把结点编号和层号建立成结构体,然后控制遍历层数不超过L。
注意点
- 由于可能形成环,必须控制每个用户只能转发消息1次(即遍历时只能访问1次)。
- 使用DFS遍历很容易出错,因为需要注意一种情况,即可能有一个用户X在第i次被访问,但是此时已经达到转发层数上限,故无法继续遍历。但若该用户可以通过另一条路径更快地被访问到,那么是可以继续深入遍历的。除此之外,DFS还可能导致同一个结点的转发次数被重复计算(需要额外设置一个数组来记录结点是否已经转发过信息,才能最终解决此问题)。本题不推荐使用DFS来写。
- 如果DFS写得不够好,就会超时,因此本题更推荐使用BFS,且BFS不会出现②中的问题,写法更直接。
const int N=1010;
vector<int> g[N];
int dep[N];
bool vis[N];
int n,m,L;
void bfs(int st)
{
queue<int> q;
q.push(st);
vis[st]=true;
dep[st]=0;
int cnt=0;
while(q.size())
{
int t=q.front();
q.pop();
ans++;
for(int i=0;i<g[t].size();i++)
{
int j=g[t][i];
dep[j]=dept[t]+1;
if(!vis[j] && dep[j] <= L)
{
vis[j]=true;
q.push(j);
}
}
}
}
int main()
{
cin>>n>>L;
for(int i=1;i<=n;i++)
{
int k;
cin>>k;
for(int j=0;j<k;j++)
{
int x;
cin>>x;
g[x].pb(i);
}
}
cin>>m;
while(m--)
{
memset(vis,0,sizeof vis);
ans=0;
int x;
cin>>x;
dfs(x,0);
cout<<endl;
cout<<ans<<endl;
}
//system("pause");
return 0;
}