POJ1236 Network of Schools 强连通分量Tarjan算法

先附上大佬博客Orz:https://blog.csdn.net/lianai911/article/details/43446089

这道题题都没读懂。。看了大佬博客才明白要干什么emmmmm...问题如下:

1、最少向几台电脑投放文件,就能使所有电脑都接收到文件。

2、最少向这n台电脑构成的图中添加几条边,就能使只向一台电脑投放文件,所有电脑都能接收到。

问题1:一开始想的是求联通块的个数,但后来想了想发现不对:可能两个联通块之间有一条单向边相连,这样其实只需要向一台电脑投放文件就可以。所以最后问题应转化为:强连通分量“缩点”后,入度为0的点的个数。

问题2:这问一开始没什么思路QAQ...看了大佬博客后发现问题转化为:强连通分量“缩点”后,在入度为0的点和出度为0的点之间最少加多少边使之构成环。那这就是max(入度为0的点,出度为0的点)。

附上AC代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
#define ll long long
typedef pair<int,int>pp;
const double pi=acos(-1.0);
const double eps=1e-9;
const int INF=0x3f3f3f3f;
const ll MOD=1e9+7ll;

const int MAX=110;
int n;
struct Edge
{
    int to,next;
}edge[MAX*MAX];
int head[MAX],tol;
int low[MAX],dfn[MAX],st[MAX],be[MAX];
int index,top;
int scc;//强连通分量的个数
bool vis[MAX];
int num[MAX];

void init()
{
    tol=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v)
{
    edge[tol].to=v;edge[tol].next=head[u];head[u]=tol++;
}
void tarjan(int u)
{
    int v;
    low[u]=dfn[u]=++index;
    st[top++]=u;
    vis[u]=true;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        v=edge[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            if(low[u]>low[v])
                low[u]=low[v];
        }
        else if(vis[v]&&low[u]>dfn[v])
            low[u]=dfn[v];
    }
    if(low[u]==dfn[u])
    {
        scc++;
        do
        {
            v=st[--top];
            vis[v]=false;
            be[v]=scc;
            num[scc]++;
        }while(v!=u);
    }
}
void solve()
{
    memset(dfn,0,sizeof(dfn));
    memset(vis,false,sizeof(vis));
    memset(num,0,sizeof(num));
    index=scc=top=0;
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i);
}

int main()
{
    while(scanf("%d",&n)==1)
    {
        init();
        int x;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            while(x!=0)
            {
                addedge(i,x);
                scanf("%d",&x);
            }
        }
        solve();
        if(scc==1)
        {
            printf("1\n0\n");
            continue;
        }
        int in[MAX],out[MAX];
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        for(int i=1;i<=n;i++)
            for(int j=head[i];j!=-1;j=edge[j].next)
            {
                int k=edge[j].to;
                if(be[i]!=be[k])
                {
                    in[be[k]]++;
                    out[be[i]]++;
                }
            }
        int nin=0,nout=0;
        for(int i=1;i<=scc;i++)//注意循环从1到scc
        {
            if(in[i]==0)
                nin++;
            if(out[i]==0)
                nout++;
        }
        int ans=max(nin,nout);
        printf("%d\n%d\n",nin,ans);
    }
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Cc_Sonia/article/details/82026308