您的位置:首页 > 其它

poj 1236-Network of Schools:Tarjan算法实现

2013-07-22 20:32 405 查看
点击打开链接

Network of Schools

Time Limit: 1000MSMemory Limit: 10000K
Total Submissions: 9214Accepted: 3654
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


第一次写tarjan算法,感觉没有想象中的难,但是还是wa了很多次,。有一些细节没弄对,在遍历图时一共有4种点:1、未搜索过的点,2、搜索过,并且在栈中的点,2、搜索过,但已经弹出的点。4、当前搜索的点。wa了很多次是因为搞错了2类和3类的点。我之前只用了一个数组,跟普通的深搜一样,搜索过就标记一下,搜索时如果遇到标记过的点就比较low值和num值,但是这样就没法区分2类和3类点,如果这个点已经标记了,而且不再栈中,这时候是不能比较low和num的值的,以为这两个点根本不在一个连通分量里,如果更新当前节点的low值,那么low会指向一个不再本强连通分量的点,正确的做法是用两个数组标记,一个标记是否搜索过,一个标记是否在栈中,如果没搜索过就继续搜,如果搜索过,还要判断一下是否在栈中,如果在栈中,则更新当前节点的low值,否则不更新,还要注意一下如果全图就是一个强连通的,那么第二个答案是0否则,第二个答案是max(入度为0的颜色的个数,出度为0的颜色的个数)。

AC代码:

#include<stdio.h>
#include<stack>
using namespace std;
stack<int> Stack;
bool map[110][110];
int n;
bool used[110];
int num[110];
int low[110];
int count;
int time;
bool instack[110];
int color[110];
int color_num;

void dfs(int node)
{
int i;

low[node] = time;
num[node] = time++;
used[node] = 1;
Stack.push(node);
instack[node] = 1;
for(i = 1; i <= n ; i++)
{
if(map[node][i] != 0)
{
if(used[i] == 1)
{
if(instack[i] == 1)
low[node] = low[node] > num[i] ? num[i] : low[node];
}
else
{
dfs(i);
low[node] = low[node] > low[i] ? low[i] : low[node];
}
}
}
int top;
if(low[node] == num[node])
{
while(!Stack.empty())
{
top = Stack.top();
Stack.pop();
instack[top] = 0;
color[top] = color_num;
if(top == node)
{
color_num++;
break;
}
}
}
}
int main()
{
//	freopen("test.txt", "r", stdin);
scanf("%d", &n);
color_num = 1;
int i;
for(i = 1; i<= n; i++)
{
int p;
while(scanf("%d", &p), p != 0)
{
map[i][p] = 1;
}
}
for(i = 1; i <= n; i++)
{
if(used[i] == 0)
{
dfs(i);
}
}
int income_used_color[110] = {0};//记录入度为0的颜色
int outcome_used_color[110] = {0};//记录出度为0的颜色
int j;
for(i = 1; i <= n; i++)
{

for(j = 1; j <= n; j++)
{
if(map[i][j] == 1)
{
if(color[i] != color[j])
{
income_used_color[color[j]] = 1;
outcome_used_color[color[i]] = 1;
}
}
}
}
int flag_income = 0;
int flag_outcome = 0;
for(i = 1; i < color_num; i++)
{
if(income_used_color[i] == 0)
flag_income ++;
if(outcome_used_color[i] == 0)
flag_outcome ++;
}
if(color_num == 2)
printf("1\n0\n");
else
printf("%d\n%d\n", flag_income, flag_income > flag_outcome? flag_income : flag_outcome);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: