POJ 1236 Network of Schools(Tarjan缩点)

Network of Schools
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 16806   Accepted: 6643

Description

A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a list of schools to which it distributes software (the “receiving schools”). Note that if B is in the distribution list of school A, then A does not necessarily appear in the list of school B 
You are to write a program that computes the minimal number of schools that must receive a copy of the new software in order for the software to reach all schools in the network according to the agreement (Subtask A). As a further task, we want to ensure that by sending the copy of new software to an arbitrary school, this software will reach all schools in the network. To achieve this goal we may have to extend the lists of receivers by new members. Compute the minimal number of extensions that have to be made so that whatever school we send the new software to, it will reach all other schools (Subtask B). One extension means introducing one new member into the list of receivers of one school.

Input

The first line contains an integer N: the number of schools in the network (2 <= N <= 100). The schools are identified by the first N positive integers. Each of the next N lines describes a list of receivers. The line i+1 contains the identifiers of the receivers of school i. Each list ends with a 0. An empty list contains a 0 alone in the line.

Output

Your program should write two lines to the standard output. The first line should contain one positive integer: the solution of subtask A. The second line should contain the solution of subtask B.

Sample Input

5
2 4 3 0
4 5 0
0
0
1 0

Sample Output

1
2

题目链接:POJ 1236

由于数据结构老师说期末成绩跟刷题数量有关(有毒),然后就去随便翻了翻校内OJ里会做的题,然后突然发现有一道题跟这题非常类似,细细查看发现题面就TM是中文翻译版本而已,而且翻译的也不好,机翻水平…………。然后时隔几个礼拜就又来做了一次这道题,这次就感觉理解更加深入了。

题目中你其实是一个超级源点,学校编号是1~n,各自均有单向边连向其他点,第一个问题是问你需要发多少个软件包来使得所有学校都可以直接、间接地获得你发的软件包;第二个问题是假如你只发一个软件包,那需要加多少条边来使得所有学校都被传达到。

对于问题一,可以发现只要一个点有入边(入度不为0),则说明他肯定可以被其他学校传递到,显然你找到入度为0的点(即没其他学校给他发软件包的点)所有点就是你要发的学校集合了,如果倒着想,不给这些点发的话肯定是无法到达的,至少这个点肯定是收不到软件包的。

对于问题二,其实问题可以转化成一个有向图(极端情况下为多个强连通分量)加多少条边变成一个强连通分量,先Tarjan缩点可以发现把边加在叶子那里效果是最好的,假如每一个人都可以传递一个能量给你,那么就需要这么一条边把尽量多的能量传出去且这样边数越少越好,显然叶子聚集的能量是最多的,最好就是从叶子连出来边加回根处,形成环,不过当强连通分量只有一个的时候就不用加了,要输出0。

代码:

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <bitset>
#include <string>
#include <deque>
#include <stack>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
typedef pair<int,int> pii;
typedef long long LL;
const double PI=acos(-1.0);
const int N=110;
struct edge
{
int to,nxt;
};
edge E[N*N*N];
int head[N],tot;
int dfn[N],low[N],belong[N],scc,ts,top,st[N];
int in[N],out[N];
bitset<N> ins; void init()
{
CLR(head,-1);
tot=0;
CLR(dfn,0);
CLR(low,0);
CLR(belong,0);
scc=ts=top=0;
CLR(in,0);
CLR(out,0);
ins.reset();
}
inline void add(int s,int t)
{
E[tot].to=t;
E[tot].nxt=head[s];
head[s]=tot++;
}
void Tarjan(int u)
{
dfn[u]=low[u]=++ts;
st[top++]=u;
ins[u]=1;
int i,v;
for (i=head[u]; ~i; i=E[i].nxt)
{
v=E[i].to;
if(!dfn[v])
{
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(ins[v])
low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
++scc;
do
{
v=st[--top];
ins[v]=0;
belong[v]=scc;
}while (u!=v);
}
}
int main(void)
{
int n,a,b,i,j;
while (~scanf("%d",&n))
{
init();
for (i=1; i<=n; ++i)
{
while (scanf("%d",&b)&&b)
add(i,b);
}
for (i=1; i<=n; ++i)
if(!dfn[i])
Tarjan(i);
for (a=1; a<=n; ++a)
{
for (j=head[a]; ~j; j=E[j].nxt)
{
int b=E[j].to;
if(belong[a]!=belong[b])
{
++out[belong[a]];
++in[belong[b]];
}
}
}
int leaf=0,root=0;
for (i=1; i<=scc; ++i)
{
if(!in[i])
++root;
if(!out[i])
++leaf;
}
printf("%d\n%d\n",root,scc==1?0:max(root,leaf));
}
return 0;
}
上一篇:电信3G上网卡自己主动重拨


下一篇:python学习1---列表、矩阵、数组