因为有点忙,加上、、、、很久没敲了, 今天一定要来一发、、、
并查集那边短路了,这个先接上,和并查集一起搞好了、、、、
(感觉还是chrome的 格式比较好看,可是竟然感觉FF更加 流畅,better!)
Description
Input
Output
Sample Input
5 2 4 3 0 4 5 0 0 0 1 0
Sample Output
1 2
kuangbin 的题解 ,感觉这才是题解!!
强连通分量缩点求入度为0的个数和出度为0的分量个数
题目大意:N(2
也就是:
给定一个有向图,求:
1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点
2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点
顶点数<= 100
解题思路:
1. 求出所有强连通分量
2. 每个强连通分量缩成一点,则形成一个有向无环图DAG。
3. DAG上面有多少个入度为0的顶点,问题1的答案就是多少
在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少
加边的方法:
要为每个入度为0的点添加入边,为每个出度为0的点添加出边
假定有 n 个入度为0的点,m个出度为0的点,如何加边?
把所有入度为0的点编号 0,1,2,3,4 ....N -1
每次为一个编号为i的入度0点可达的出度0点,添加一条出边,连到编号为(i+1)%N 的那个出度0点,
这需要加n条边
若 m <= n,则
加了这n条边后,已经没有入度0点,则问题解决,一共加了n条边
若 m > n,则还有m-n个入度0点,则从这些点以外任取一点,和这些点都连上边,即可,这还需加m-n条边。
所以,max(m,n)就是第二个问题的解
此外:当只有一个强连通分支的时候,就是缩点后只有一个点,虽然入度出度为 0的都有一个,但是实际上不需要增加清单的项了,所以答案是 1, 0;
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 20010; //点数
const int MAXM = 50010; //边数
struct Edge
{
int to, next;
}edge[MAXM];
int in_edge[MAXM];
int out_edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN]; //Belong数组的值是1~scc
int Index,top;
int scc; //强连通分量的个数
bool Instack[MAXN];
int num[MAXN]; //各个强连通分量包含点的个数,数组编号1~scc
//num数组不一定需要,结合实际情况
void addedge(int u, int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void Tarjan(int u)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for(int i = head[u]; i != -1; i = edge[i].next)
{
v = edge[i].to;
if( !DFN[v] )
{
Tarjan(v);
if( Low[u] > Low[v] )
Low[u] = Low[v];
}
else if(Instack[v] && Low[u] > DFN[v])
Low[u] = DFN[v];
}
if(Low[u] == DFN[u])
{
scc++;
do
{
v = Stack[ --top];
Instack[v] = false;
Belong[v] = scc;
num[scc]++;
}
while( v != u);
}
}
void solve(int N)
{
memset(DFN, 0, sizeof(DFN));
memset(Instack, false, sizeof(Instack));
memset(num, 0, sizeof(num));
Index = scc = top = 0;
for(int i = 1;i <= N; i++)
if(!DFN[i])
Tarjan(i);
}
void init()
{
tot = 0;
memset(head, -1, sizeof(head));
}
int main()
{
int n, m;
int tmp_1, tmp_2;
while(~scanf("%d",&n))
{
init();
for(int i = 1; i <= n; i ++)
{
while(~scanf("%d",&m), m)
{
addedge(i, m);
}
}
solve(n);
if(scc == 1)
{
printf("1\n0\n");
continue;
}
for(int i = 1; i <= n; i ++)
{
for(int j = head[i]; j != -1; j = edge[j].next)
{
int v = edge[j].to;
if(Belong[i] == Belong[v])
{
continue;
}
in_edge[Belong[v]] ++;
out_edge[Belong[i]] ++;
}
}
tmp_1 = tmp_2 = 0;
for(int i = 1; i <= scc; i ++)
{
if(in_edge[i] == 0)
tmp_1 ++;
if(out_edge[i] == 0)
tmp_2 ++;
}
printf("%d\n%d\n", tmp_1, max(tmp_1, tmp_2));
}
}