[USACO5.3]校园网Network of Schools Tarjan缩点

来源:互联网 发布:频率发生器软件 编辑:程序博客网 时间:2024/06/05 06:58

题目描述
题目

对于任务A,即求缩点后入度为0的点的个数
对于任务B,要使整个图连通,则入度0的点需要拓展一条入边,出度0的点需要拓展一条出边,那么需要拓展的最少边数即为max(入度0点数,出度0点数);特别的,当本来整个图连通时,不需要拓展

代码

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;const int N=110,M=N*N;int ans,n,top,cnt1,cnt2,s[N],deg[N],q[N],e[N][N];int tot,idx,dfn[N],low[N],col[N],vis[N];vector<int>g[N];int read(){    int out=0,f=1;char c=getchar();    while(c > '9' || c < '0') {if(c == '-') f=-1; c=getchar();}    while(c <= '9' && c >= '0') {out=(out<<1)+(out<<3)+c-'0';c=getchar();}    return out*f;}void init(){    n=read();    for(int i=1;i<=n;i++)    {        int x;        while(x=read()) {g[i].push_back(x);}    }}void tarjan(int u){    dfn[u]=low[u]=++idx;s[++top]=u;vis[u]=1;    for(unsigned int i=0;i<g[u].size();i++)    {        int v=g[u][i];        if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);}        else if(vis[v]) low[u]=min(low[u],dfn[v]);    }    if(dfn[u] == low[u])    {        tot++;int x=0;        while(x != u)        {            x=s[top--];            col[x]=tot;            vis[x]=0;        }    }}void topo(){    int head=0,tail=0;    for(int i=1;i<=tot;i++) if(!deg[i]) q[tail++]=i,cnt1++;    while(head < tail)    {        int u=q[head++],flag=0;        for(int i=1;i<=tot;i++)        if(e[u][i])        {            deg[i]--;flag=1;            if(!deg[i]) q[tail++]=i;        }        if(!flag) cnt2++;    }}void solve(){    for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);    for(int i=1;i<=n;i++)        for(unsigned int j=0;j<g[i].size();j++)        {            int v=g[i][j];            if(col[i] != col[v] && !e[col[i]][col[v]])            {                deg[col[v]]++;                e[col[i]][col[v]]=1;            }           }    if(tot == 1) {printf("%d\n%d\n",1,0);   return ;}    topo();    printf("%d\n%d\n",cnt1,max(cnt1,cnt2));}int main(){    init();    solve();    return 0;}
原创粉丝点击