POJ 1236 Network of Schools【强连通分量+缩点】
题意: 知道了N 个学校,以及每个学校提供软件支持的学校编号,一个学校得到软件支持之后便可以支持他能支持的学校,问至少对多少学校提供软件支持可以使得
所有学校都得到软件支持,和至少在这些学校添加多少条边能使得任何一个学校得到软件支持后,其他所有学校都能得到软件支持。
分析: 先求出所有的强连通分量并进行染色缩点,找出入度为 0 的强连通分量,其个数即为使所有学校得到支持所需要提供软件支持的最小数量, 而根节点与叶子节点
数量中的最大值即为最少添加的边数。
#include<stdio.h> #include<string.h> #define clr(x)memset(x,0,sizeof(x)) struct node { int to,next; }e[20000]; int tot; int head[102]; void add(int s,int u) { e[tot].to=u; e[tot].next=head[s]; head[s]=tot++; } int ti,sn,top; int col[102]; int dfn[102],low[102],stack[102]; bool ins[102]; void tarjan(int u) { dfn[u]=low[u]=++ti; stack[++top]=u; ins[u]=true; int i,k; for(i=head[u];i;i=e[i].next) { k=e[i].to; if(dfn[k]==0) { tarjan(k); if(low[k]<low[u]) low[u]=low[k]; } else if(ins[k]&&dfn[k]<low[u]) low[u]=dfn[k]; } if(dfn[u]==low[u]) { sn++; do { k=stack[top--]; col[k]=sn; ins[k]=false; }while(k!=u); } } int id[102]; int od[102]; int main() { int n,i,j,k,p,flag,in,out; while(scanf("%d",&n)!=EOF) { tot=1; top=0; ti=sn=0; clr(low); clr(dfn); clr(ins); clr(head); clr(id); clr(od); for(i=1;i<=n;i++) { while(scanf("%d",&p),p) add(i,p); } for(i=1;i<=n;i++) if(dfn[i]==0) tarjan(i); in=out=0; for(i=1;i<=n;i++) for(j=head[i];j;j=e[j].next) { k=e[j].to; if(col[i]!=col[k]) { id[col[k]]++; od[col[i]]++; } } for(i=1;i<=sn;i++) { if(id[i]==0) in++; if(od[i]==0) out++; } printf("%d\n",in); if(sn==1) printf("0\n"); else printf("%d\n",in>out?in:out); } return 0; }