zoukankan      html  css  js  c++  java
  • 机房测试11:信息拦截 (tarjan缩点+正反拓扑)

    题目:

     分析:

    这道题真的毒瘤,思想很简单,但是细节很多。。

    题意:找到从1~n的必经点(每条信息都能获取),且不在一个点数>=2 的强连通分量中(恰好获取一次)。

    先将有向图缩点,转换成一张有向无环图。

    然后对缩点后的图进行正反拓扑,求出必经点。

    再看必经点是否在一个点数>=2的强联通分量中。

    正反拓扑过程:

     fs[u]表示从起点到u的路径条数,ft[u]表示从终点到u的路径条数

    由乘法原理可知,若一个点满足:fs[u]*ft[u]==fs[t]

    这个点是必经点。

    细节:

    1. 对于存在自环的点,一定不能为最后答案,所以要用self标记一下。

    2. 要求用按照遍历顺序输出,要用拓扑序记录一下遍历顺序。

    3. 缩点从1出发,而不是将整张图的强联通分量都找出来!!

    4. 拓扑的起点为1,终点为n。

    5. 缩点后的连边可能会有重边,但这并不影响答案。

    6. 路径数会很大,对大质数取模即可(可能会冲突)。

    #include<bits/stdc++.h>
    using namespace std;
    #define ri register int
    #define N 1000005
    #define ll long long
    const ll mod=1e9+7;
    int read()
    {
        int x=0,fl=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') fl=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x*fl;
    }
    int n,m,tot=0,cnt=0,Ti=0,head[N],nex[N],to[N],fa[N],self[N];
    int dfn[N],low[N],stk[N],top=0,bel[N],ru1[N],ru2[N],flag[N],siz[N];
    ll fs[N],ft[N];
    vector<int> e1[N];
    vector<int> e2[N];
    vector<int> ans;
    vector<int> scc[N];
    void init()
    {
        tot=Ti=cnt=top=0; ans.clear();
        for(ri i=1;i<=max(tot,n);++i) 
        self[i]=siz[i]=dfn[i]=low[i]=stk[i]=bel[i]=ru1[i]=ru2[i]=head[i]=fs[i]=ft[i]=flag[i]=0,e1[i].clear(),e2[i].clear(),scc[i].clear();
    }
    void add(int a,int b) { if(a==b) { self[a]=true; return ; } to[++tot]=b; nex[tot]=head[a]; head[a]=tot; }
    void tarjan(int x)
    {
        dfn[x]=low[x]=++Ti;
        if(x==n) siz[x]=1;
        stk[++top]=x; flag[x]=true;
        for(ri i=head[x];i;i=nex[i]){
            int v=to[i];
            if(!dfn[v]){
                tarjan(v);
                low[x]=min(low[x],low[v]);
            }
            else if(flag[v]) low[x]=min(low[x],dfn[v]);
            siz[x]|=siz[v];
        }
        if(dfn[x] == low[x]){
            cnt++;
            do{
                int xx=stk[top];
                scc[cnt].push_back(xx); flag[xx]=false;
                bel[xx]=cnt;
            }while(stk[top--]!=x);
        }
    }
    queue<int> q;
    int tup[N];
    void topu()
    {
        int num=0;
        q.push(bel[1]); fs[bel[1]]=1;
        while(!q.empty()){
            int u=q.front(); q.pop();
            tup[++num]=u;
            for(ri i=0;i<e1[u].size();++i){
                int v=e1[u][i];
                fs[v]=fs[v]+fs[u];
                if(fs[v]>=mod) fs[v]%=mod;
                if(--ru1[v]==0) q.push(v);
            }
        }
        q.push(bel[n]); ft[bel[n]]=1;
        while(!q.empty()){
            int u=q.front(); q.pop();
            for(ri i=0;i<e2[u].size();++i){
                int v=e2[u][i];
                ft[v]=ft[v]+ft[u];
                if(ft[v]>=mod) ft[v]%=mod;
                if(--ru2[v]==0) q.push(v);
            }
        }
        for(ri i=1;i<=num;++i){
            int u=tup[i];
            if( fs[u]*ft[u]%mod==fs[bel[n]] && scc[u].size()==1 && !self[scc[u][0]]) ans.push_back(scc[u][0]);
        }
        printf("%d
    ",ans.size());
        for(ri i=0;i<ans.size();++i) printf("%d ",ans[i]);
        printf("
    ");
    }
    int main()
    {
        freopen("i.in","r",stdin);
        freopen("i.out","w",stdout);
        int T=read();
        while(T--){
            init();
            n=read(), m=read();
            int a,b;
            for(ri i=1;i<=m;++i) a=read(),b=read(),add(a,b);
            tarjan(1);
            for(ri i=1;i<=n;++i)
             if(dfn[i] && siz[i])
              for(ri j=head[i];j;j=nex[j]){
                 int v=to[j]; 
                 if(bel[i]==bel[v] || !siz[v]) continue;//chong bian
                 e1[bel[i]].push_back(bel[v]);
                 ru1[bel[v]]++;
                 e2[bel[v]].push_back(bel[i]);
                 ru2[bel[i]]++;
            }
            topu();
        }
    }
    /*
    6
    4 3
    2 4
    1 3
    3 2
    
    2 2
    1 2
    2 1
    
    3 1
    2 3
    
    4 4
    1 2
    2 4
    3 4
    1 3
    
    6 6
    1 3
    3 2
    2 1
    1 4
    5 4
    4 6
    
    7 9
    1 2
    2 4
    2 3
    4 3
    3 6
    6 3
    3 5
    6 5
    5 7
    */
    View Code
  • 相关阅读:
    TypeScript完全解读(26课时)_2.TypeScript完全解读-基础类型
    Flutter实战视频-移动电商-48.详细页_详情和评论的切换
    Flutter实战视频-移动电商-47.详细页_Flutter_html插件的使用
    TypeScript完全解读(26课时)_1.TypeScript完全解读-开发环境搭建
    [Android] The connection to adb is down, and a severe error has occured
    每日一小练——求质数
    C++语言笔记系列之十八——虚函数(1)
    Android 输入管理服务-输入事件向详细应用的分发
    Android技术归档
    C++编写绚丽的界面
  • 原文地址:https://www.cnblogs.com/mowanying/p/11650896.html
Copyright © 2011-2022 走看看