poj 1236 - Network of Schools

题目来源: http://acm.pku.edu.cn/JudgeOnline/problem?id=1236

 

这是一道强连通分量的题目。

题意: 

网络中有一些学校,每个学校可以分发软件给其他学校。可以向哪个分发取决于他们各自维护的一个清单。

有两个问题,1:至少要copy多少份新软件给那些学校, 才能使得每个学校都能得到。

2:要在所有的学校的清单里面至少一共增加几项才能 使得  把软件给任意一个学校,所有的学校都能收得到。

 

思路: 

       整个就是一个有向图啊, 学校是节点, 它的表里面有从他出发到其他节点的边。

       问题一: 要使每个学校都能收到,就是计算图里面一共有多少入度是0的点,这个好理解。

      问题二: 先学习下计算强连通分支的算法——Tarjan,  然后缩点,把每一块看成一个点,出来一个新的有向图。然后计算出度为0的入度为0的点各有多少, 大的那个就是答案。 

值得注意的是, 当只有一个强连通分支的时候,就是缩点后只有一个点,虽然入度出度为0的都有一个,但是实际上不需要增加清单的项了,所以答案是1,0;

 

 

 

 
  
1 #include < iostream >
2   using namespace std;
3
4   const int M = 105 ;
5
6   struct Node
7 {
8 int to;
9 Node * next;
10 };
11 Node * g[M];
12 int low[M], stack[M], ord[M], id[M];
13 int cnt, scnt;
14 bool instack[M], map[M], in [M], out [M];
15
16
17
18 void init( int n)
19 {
20 for ( int i = 1 ; i <= n; i ++ )
21 {
22 in [i] = true ;
23 out [i] = true ;
24 low[i] = 0 ;
25 ord[i] = 0 ;
26 id[i] = 0 ;
27 instack[i] = false ;
28 map[i] = true ;
29 }
30 }
31
32 void insert( int u, int v)
33 {
34 Node * tmp = new Node;
35 tmp -> to = v;
36 tmp -> next = g[u];
37 g[u] = tmp;
38 }
39
40 void Tarjan( int n, int e)
41 {
42 cnt ++ ;
43 low[e] = ord[e] = cnt;
44 instack[e] = true ;
45 stack[ ++ stack[ 0 ]] = e;
46 Node * tmp = g[e];
47
48 while (tmp != NULL)
49 {
50 int t = tmp -> to;
51 if ( ! ord[t])
52 {
53 Tarjan(n, t);
54 if (low[e] > low[t])
55 low[e] = low[t];
56 }
57 else if (instack[t] && ord[t] < low[e])
58 low[e] = ord[t];
59
60 tmp = tmp -> next;
61 }
62
63 if (low[e] == ord[e])
64 {
65 int t;
66 scnt ++ ;
67 do
68 {
69 t = stack[stack[ 0 ] -- ];
70 id[t] = scnt;
71 instack[t] = false ;
72
73 } while (t != e);
74 }
75
76 return ;
77 }
78
79 void find_compentents( int n)
80 {
81 cnt = scnt = 0 ;
82 stack[ 0 ] = 0 ;
83 for ( int i = 1 ; i <= n; i ++ )
84 {
85 if ( ! ord[i])
86 Tarjan(n, i);
87 }
88 return ;
89 }
90
91 int main()
92 {
93 int n;
94 while (scanf( " %d " , & n) != EOF)
95 {
96 init(n);
97 for ( int i = 1 ; i <= n; i ++ )
98 {
99 while ( 1 )
100 {
101 int a;
102 scanf( " %d " , & a);
103 if (a == 0 )
104 break ;
105 // out[i] = false;
106 // in[a] = false;
107 insert(i, a);
108 }
109 }
110
111 find_compentents(n);
112
113 int ansin = 0 , ansout = 0 ;
114 for ( int i = 1 ; i <= n; i ++ )
115 {
116 Node * tmp;
117 tmp = g[i];
118 while (tmp != NULL)
119 {
120 int e = tmp -> to;
121 if (id[i] != id[e] && out [id[i]])
122 out [id[i]] = false ;
123 if (id[i] != id[e] && in [id[e]])
124 in [id[e]] = false ;
125 tmp = tmp -> next;
126 }
127 }
128
129 for ( int i = 1 ; i <= scnt; i ++ )
130 {
131 if ( in [i])
132 ansin ++ ;
133 if ( out [i])
134 ansout ++ ;
135 }
136
137 if (scnt == 1 )
138 ansout = 0 ;
139 else
140 ansout = ansout > ansin ? ansout:ansin;
141 printf( " %d\n%d\n " ,ansin,ansout);
142
143
144 }
145 return 0 ;
146 }
147

 

 

 

 

转载于:https://www.cnblogs.com/zhjjla/archive/2010/05/22/1741436.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值