Improve SPAM(拓扑+BFS)

Gym 102428I Improve SPAM

题意

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

思路

建图,跑一遍bfs可以求出能到达几个接收点,同时优化得到一个连通图。每个接受点受到的邮件数目等于所有上一级发送的邮件数目之和。所以跑一遍拓扑排序即可,每次更新该点可以接收邮件数目
ci[edge[i].to] = ci[p] + ci[edge[i].to]

#include <iostream>
#include <algorithm>
#include <string>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>

using namespace std;

typedef long long ll;

const int maxn = 2e3 + 10;
const int mod = 1e9+7;

struct Node
{
    int to,next;
    int flag=0;//是否为连通图
}edge[maxn * maxn];

int head[maxn];
int in[maxn];
int ci[maxn];
int cnt;
ll ans1,ans2;
int vis[maxn];
int n,m;

queue <int> Q;

void addage(int u, int v, int mark = 0) //链式前向星存储图
{
    if(!mark) //第一遍求接受点不需要求每个点的入度
    {
        cnt++;
        edge[cnt].to = v;
        edge[cnt].next = head[u];
        head[u] = cnt;
    }
    if(mark) //优化后的连通图直接求入度
        in[v]++;
}

void bfs() //寻找有几个有效的接收点
{
    ans2 = 0;
    while(!Q.empty()) Q.pop();
    memset(vis,0,sizeof(vis));
    Q.push(1);
    vis[1] = 1;
    while(!Q.empty())
    {
        int p = Q.front();
        Q.pop();
        if(p>m)
            ans2++;
        for(int i = head[p]; i; i = edge[i].next)
        {
            addage(p,edge[i].to,1); //存在通路的标记
            if(!vis[edge[i].to])
            {
                vis[edge[i].to] = 1;
                Q.push(edge[i].to);
            }
        }
    }
}

void topu() //算总共受到多少邮件
{
    memset(ci,0,sizeof(ci));
    while(!Q.empty())
        Q.pop();
    Q.push(1);
    ci[1] = 1;
    while(!Q.empty())
    {
        int p = Q.front();
        Q.pop();
        for(int i = head[p]; i != 0; i = edge[i].next)
        {
            ci[edge[i].to] = (ci[p] + ci[edge[i].to]) % mod; //求出每个点接收到的数目
            in[edge[i].to]--;  //入度减1
            if(in[edge[i].to] == 0)
            {
                Q.push(edge[i].to);  //当入度为0时,收到的数目已经确定,就可以入队列搜下一层
            }
        }
    }
    ans1 = 0;
    for(int i = m + 1; i <= n; i++)
        ans1 = (ans1 + ci[i]) % mod;
}

int main()
{
        cin>>n>>m;
        for(int i = 1;i <= m;i++)
        {
            int a;
            cin>>a;
            for(int j = 1;j <= a;j++)
            {
                int b;
                scanf("%d",&b);
                addage(i,b);
            }
        }
        bfs();
        topu();
        cout<<ans1<<' '<<ans2;
        return 0;
}


已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页