POJ1236_Network of Schools_强连通分量_Korasaju算法

来源:互联网 发布:数据库删除一行数据 编辑:程序博客网 时间:2024/05/16 13:00

题意:

给一个有向图,task_A:选最少的点使之可以遍历整个图

task_B:添加最少的边使图成为强连通图


题解:

A:

    有向无环图中所有入度不为0的点,一定可以由某个入度为0的点出发可达。(由于无环,所以从任何入度不为0的点往回走,必然终止于一个入度为0的点)  

1. 求出所有强连通分量
2. 每个强连通分量缩成一点,则形成一个有向无环图DAG。
3. DAG上面有多少个入度为0的顶点,问题1的答案就是多少

B:

在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少
加边的方法:
要为每个入度为0的点添加入边,为每个出度为0的点添加出边
假定有n 个入度为0的点,m个出度为0的点,max(m,n)就是第二个问题的解(证明难,略)


【PS:代码的核心几乎跟上一题的POJ2186一样,就直接复制过来改改就A了,不过要注意只有一个强连通分量的时候,添加边为0】

原题:


Network of Schools
Time Limit: 1000MS
Memory Limit: 10000KTotal Submissions: 9179
Accepted: 3642

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

52 4 3 04 5 0001 0

Sample Output

12

Run IDUserProblemResultMemoryTimeLanguageCode LengthSubmit Time11824845chengtbf1236Accepted244K32MSC++2771B2013-07-21 09:07:25


代码:


#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#define N 105#define M 10005using namespace std;typedef struct MyStruct{int u,v;}EDGE;EDGE edge[M];int n,m;int visited_first[N];//记录第一次搜索过程中是否被访问过int visited_second[N];//记录第二次搜索过程中是否被访问过vector<int>G[N];//存图vector<int>G_t[N];//存转置图int dfs_time;int end_time[N];//这里非常巧妙!!!end_time[i]不是代表第i个结点的结束时间,而是结束时间为i的结点序号//!这样就直接省去了一次复杂的排序!而且结束时间与结点标号一一对应!int color[N];//用不同的颜色标记不同的强连通分量int dfs_color;//记录颜色的变量int num_of_color[N];//记录强连通分量内的结点个数int degree_in[N];//记录不同强连通分量形成的缩点的入度int degree_out[N];//记录出度void dfs_first(int u)//第一次深搜搜原图记录结束时间{visited_first[u]=1;int child;for (int i = 0; i <G[u].size(); i++){child=G[u][i];if (!visited_first[child]){dfs_first(child);}}end_time[dfs_time++]=u;}void dfs_second(int u)//第二次深搜搜转置图求强联通分量{visited_second[u]=1;color[u]=dfs_color;//标记当前结点的颜色num_of_color[dfs_color]++;int child;for (int i = 0; i < G_t[u].size(); i++){child=G_t[u][i];if (!visited_second[child]){dfs_second(child);}}}int main(){int i,j,a,b,u,flag,ans_A,ans_B;while (scanf("%d",&n)!=EOF){//这应该是我做的最坑爹的一次初始化了- -这么多数组for ( i = 0; i <=n ; i++){G[i].clear();G_t[i].clear();}memset(visited_first,0,sizeof(visited_first));memset(visited_second,0,sizeof(visited_second));memset(end_time,0,sizeof(end_time));memset(color,0,sizeof(color));memset(num_of_color,0,sizeof(num_of_color));memset(degree_in,0,sizeof(degree_in));memset(degree_out,0,sizeof(degree_out));dfs_color=1;dfs_time=1;flag=0;//flag变量标记是否有多个出度为0的强连通分量ans_A=0;j=1;ans_B=0;for ( i = 1; i <=n ; i++){while (scanf("%d",&b),b!=0){G[i].push_back(b);//正向存图,a指向bG_t[b].push_back(i);//反向存,存转置图edge[j].u=i;edge[j].v=b;j++;}}m=j-1;for ( i = 1; i <=n ; i++){if (!visited_first[i]){dfs_first(i);}}for ( i =n ; i > 0 ; i--){u=end_time[i];if (!visited_second[u])//此标记表示 结束时间为i的结点(是u)是否被访问过{dfs_second(u);dfs_color++;}}for (i = 1; i <=m ; i++){if (  color[ edge[i].u ]  !=  color[ edge[i].v ])//如果当前边的两个结点的颜色不一样,说明分别属于不同的强连通分量{degree_out[ color[ edge[i].u ] ]++;//则结点u的颜色所代表的强连通分量的出度加一degree_in[ color[ edge[i].v ] ]++;//则结点v的颜色所代表的强连通分量的入度加一}}for ( i = 1; i <dfs_color ; i++){if (degree_in[i]==0){ans_A++;}if (degree_out[i]==0){ans_B++;}}ans_B=ans_A>ans_B?ans_A:ans_B;if (dfs_color==2){printf("1\n0\n");}else{printf("%d\n%d\n",ans_A,ans_B);}}return 0;}


原创粉丝点击