wannafly挑战赛14 C可达性

src:https://www.nowcoder.com/acm/contest/81/C

输出一个尽可能小的点集,使得从这些点出发能够到达任意一点,如果有多个这样的集合,输出这些集合升序排序后字典序最小的。

缩点后入度为0的都是了~~~

ac代码:

#include <iostream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<functional>
#include<utility>
#include<string>
#include<string.h>
#include<vector>
#include<iomanip>
#include<stack>
using namespace std;
#define FOR(i,a,b) for(int i=a;i<=b;i++)

vector<int>edge[100005],ans;
int n,m,vis[100005],a,b,idx=0,scc[100005],nscc=0,in[100005],tmp,dfn[100005],low[100005];//in表示强分量入度
stack<int>st;
vector<int>id[100005];
bool InStack[100005];

void tarjan(int u)
{
    dfn[u]=low[u]=++idx;
    st.push(u);InStack[u]=true;
    for(vector<int>::iterator it=edge[u].begin();it!=edge[u].end();++it)
    {
        if(!dfn[*it]){
            tarjan(*it);low[u]=min(low[u],low[*it]);
        }
        else if(InStack[*it]) low[u]=min(low[u],dfn[*it]);
    }
    if(dfn[u]==low[u]){
        nscc++;
        do{
            tmp=st.top();st.pop();
            InStack[tmp]=false;
            scc[tmp]=nscc;
            id[nscc].push_back(tmp);
        }while(tmp!=u);
    }
}
void condense()
{
    for(int i=1;i<=n;++i){
        if(dfn[i]==0){
            tarjan(i);
        }
    }
}

int main()
{
    std::ios::sync_with_stdio(false);
    cin>>n>>m;
    int tmp;
    for(int i=1;i<=m;i++){
        cin>>a>>b;
        if(a==b)continue;
        edge[a].push_back(b);
    }
    condense();
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=n;i++){
        for(vector<int>::iterator it=edge[i].begin();it!=edge[i].end();++it){
            tmp=*it;
            if(scc[i]!=scc[tmp]){in[scc[tmp]]++;}
        }
    }
    FOR(i,1,nscc)sort(id[i].begin(),id[i].end());
    vector<int>ans;
    for(int i=1;i<=nscc;i++)if(!in[i])ans.push_back(id[i][0]);
    cout<<ans.size()<<endl;
    sort(ans.begin(),ans.end());
    cout<<ans[0];
    for(int i=1;i<ans.size();i++)cout<<' '<<ans[i];
    cout<<endl;

    return 0;
}

 

posted @ 2018-04-21 16:11  WindFreedom  阅读(139)  评论(0)    收藏  举报