poj1236 - Network of Schools(强连通分量Garbow模板+缩点)

题意:
给出n个学校,每个学校都有receiving school,第一问求的是从外部分发给最少的学校,所有的学校都能收到,第二问就是加多少receiving school可以使得从任意学校发一个软件,其他全部学校都能收到。
思路:
求出强连通分量后,将每个强连通分量缩成一个点,得到一个DAG。接下来第一问的答案就是入度为0的点的个数,第二问是入度为0的点的个数与出度为0的个数两者的最大值。
(当整个图都是连通,即只有一个强连通分量时,第一问答案是1,第二问答案是0)

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <stack>
#include <vector>
#include <string.h>
#include <queue>
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;
const int MAXN=110;
struct _Edge
{
    int frm,to,next;
}edge[MAXN*MAXN];
int hd[MAXN],tot;
int Low[MAXN],Sta1[MAXN],Sta2[MAXN],Belong[MAXN];
int num[MAXN];//下标1~scc
bool in[MAXN],out[MAXN];
int scc,Index,stp1,stp2;
void addedge(int u,int v)
{
    edge[tot].frm=u;
    edge[tot].to=v;
    edge[tot].next=hd[u];
    hd[u]=tot++;
}
void Garbowbfs(int u)
{
    Sta1[stp1++]=u;
    Sta2[stp2++]=u;
    Low[u]=++Index;
    for(int i=hd[u];i!=-1;i=edge[i].next)
    {
        if(!Low[edge[i].to])
            Garbowbfs(edge[i].to);
        else if(!Belong[edge[i].to]){
            while(Low[Sta2[stp2-1]]>Low[edge[i].to])
                --stp2;
        }
    }
    if(Sta2[stp2-1]==u){
        stp2--;
        scc++;
        int v;
        do{
            v=Sta1[--stp1];
            num[scc]++;
            Belong[v]=scc;
        }while(v!=u);
    }
}
int main(int argc, char const *argv[])
{
    int n;
    cin>>n;
    msc(hd);
    ms(in);
    tot=0;
    for(int i=1;i<=n;i++)
    {
        int tmp;
        while(scanf("%d",&tmp)!=EOF&&tmp)
            addedge(i,tmp);
    }
    scc=Index=stp1=stp2=0;
    ms(Belong);
    ms(Low);
    ms(num);
    for(int i=1;i<=n;i++)
        if(!Low[i]) Garbowbfs(i);
    if(scc==1) {puts("1\n0");return 0;}
    for(int i=0;i<tot;)
    {
        edge[i].frm=Belong[edge[i].frm];
        edge[i].to=Belong[edge[i].to];
        if(edge[i].frm==edge[i].to)
            swap(edge[i],edge[--tot]);
        else i++;
    }
    ms(in);
    ms(out);
    int in0=0,out0=0;
    for(int i=0;i<tot;i++)
        in[edge[i].to]=out[edge[i].frm]=true;
    for(int i=1;i<=scc;i++)
    {
        if(!in[i]) in0++;
        if(!out[i]) out0++;
    }
    printf("%d\n%d\n",in0,max(in0,out0) );
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值