题目链接:http://poj.org/problem?id=1236
题目大意:给出N台电脑,电脑间单向连通传送文件
问题1.网络中最少放几个文件保证所有电脑都能接受到文件
问题2.最少向网络中加几条线保证任意放1个文件所有电脑都能接受到
解题思路:
1.求出强连通分量
2.缩点 ,进行重新构图
3.如果入度为0,说明没有文件传输到该网络。解决问题1,统计入度为0的个数即可
4.一个强连通图的入度和出度都不为0。入度为0相当于根root,出度为0相当于叶子leave.max(root, leave)即为答案。
就是需要加的线数,保证整个网络强连通。
若连通分量个数为0,那么答案为0
代码如下:
#include<stdio.h> #include<string.h> #include<iostream> using namespace std; #define N 105 #define M 10005 struct Edge { int v, next; }edge[M]; int node[N], stack[N], instack[N], dfn[N], out[N], in[N]; int low[N], belong[N], index, cnt_edge, n, m, cnt_tar, top; int ee[M][2]; void add_Edge(int u, int v) { edge[cnt_edge].next=node[u]; edge[cnt_edge].v=v; node[u]=cnt_edge++; } void tarjan(int u) { int i, j, v; dfn[u]=low[u]=++index; stack[++top]=u; instack[u]=1; for(i=node[u]; i!=-1; i=edge[i].next) { v=edge[i].v; if(!dfn[v]) { tarjan(v); low[u]=min(low[u], low[v]); } else if(instack[v]) low[u]=min(low[u], dfn[v]); } if(dfn[u]==low[u]) { cnt_tar++; do { j=stack[top--]; instack[j]=0; belong[j]=cnt_tar; }while(j!=u); } } void solve() { int i; top=0, index=0, cnt_tar=0; memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); for(i=1; i<=n; i++) if(!dfn[i]) tarjan(i); } int main() { int i, u, v; while(scanf("%d", &n)!=EOF) { cnt_edge=0, m=1; memset(node, -1, sizeof(node)); memset(in, 0, sizeof(in)); memset(out, 0, sizeof(out)); for(i=1; i<=n; i++) { while(scanf("%d", &v)) { if(v==0) break; ee[m][0]=i, ee[m++][1]=v; add_Edge(i, v); } } solve(); for(i=1; i<=m; i++) { int xx=belong[ee[i][0]], yy=belong[ee[i][1]]; if(xx!=yy) { in[yy]++; out[xx]++; } } int innum=0, outnum=0; for(i=1; i<=cnt_tar; i++) { if(in[i]==0) innum++; if(out[i]==0) outnum++; } if(cnt_tar==1) printf("1 0 "); else printf("%d %d ", innum, max(innum, outnum)); } return 0; }