poj1236 Network of Schools(tarjan)

poj1236
- 题意:n个电脑直接有一些有向边(u,v)。下发文件时,如果u得到了且有一条边(u,v),那么v也就得到了。
– 问1:最少下发多少份文件使得所有电脑能接收到文件
– 问2:至少加多少条使得从任意一个地方下发文件,所有人都能够看的到


  • 第一问,也就是求有多少个强连通块入度为0。
    因为,每个强连通块内都是可以互相到达的,然后..如果这个强连通块入度不为零,那么说明至少会有一个强连通块连向它,那么那个强连通块如果有了文件,次强连通块内的点也就有了文件。
    所以,我们只要找到强连通块的入度为零的点的个数就好啦~
  • 第二问,也就是求最少添加多少条边成为强连通块。
    就如同上一问,只考虑每个强连通块直接的关系就好了。我们可以把没有出度的连向没有入度的,这样就能使得边最少了。然后剩下的就随便连就好了
    所以,结果就是 max(入度为零的点的个数m,出度为零的点的个数)

#include <cstdio>
#include <algorithm>
using namespace std;
#define N 110
struct node{int x,y,next;}mp[N*N];
int dfn[N],stack[N],vis[N],low[N],h[N],belong[N],cnt1[N],cnt2[N],tot=0,num=0,n,top=0,scc=0,ans1=0,ans2=0;
void tarjan(int x){
    dfn[x]=++tot;low[x]=tot;
    vis[x]=1;stack[++top]=x;
    for(int i=h[x];i;i=mp[i].next){
        int y=mp[i].y;
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }else if(vis[y]) low[x]=min(low[x],dfn[y]);
    }if(dfn[x]==low[x]){
        belong[x]=++scc;vis[x]=0;
        while(stack[top]!=x){
            belong[stack[top]]=scc;
            vis[stack[top--]]=0;
        }top--;
    }
}
int main(){
    freopen("poj1236.in","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int x;
        while(scanf("%d",&x)>0 && x>0){mp[++num].x=i;mp[num].y=x;mp[num].next=h[i];h[i]=num;}
    }
    for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
    for(int i=1;i<=num;i++){
        int x=belong[mp[i].x],y=belong[mp[i].y];
        if(x!=y){cnt1[x]++;cnt2[y]++;}
    }
    if(scc==1) {printf("1\n0\n");return 0;}//注意!!!
    for(int i=1;i<=scc;i++){
        if(!cnt1[i]) ans1++;
        if(!cnt2[i]) ans2++;
    }
    printf("%d\n%d\n",ans2,max(ans1,ans2));
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值