Network of Schools POJ - 1236

5 篇文章 0 订阅

 

#include <string.h>
#include<iostream>
#include <stdio.h>

const int V = 105; 
const int E = 1005;

const int inf = 0x3f3f3f3f;

using namespace std;

struct edge {
	int to, next;
} Edge[E];

int head[V], e, n, m;
int indeg[V], outdeg[V]; //点的入度和出度数
int belong[V], low[V], dfn[V], scc, cnt;//dfn[]:遍历到u点的时间; low[]:u点可到达的各点中最小的dfn[v]
int S[V], top;

bool vis[V];//v是否在栈中
bool cut[V];

int addedge(int u, int v) {
	Edge[e].to = v;
	Edge[e].next = head[u];

	head[u] = e++;

	return 0;
}

//int cont = 0;
void tarjan(int u) {
	int v;

	dfn[u] = low[u] = ++cnt;
	S[top++] = u;

	vis[u] = true;

	for (int i=head[u]; i!=-1; i=Edge[i].next) {
		v = Edge[i].to;

		if (dfn[v] == 0) { //v点未遍历
			tarjan(v);
			low[u] = low[u] < low[v] ? low[u] : low[v];//回溯保证low为所联系的最小值
		}
		else if (vis[v] && low[u] > dfn[v])//v在栈中,修改low[u]
			low[u] = dfn[v];
	}
	if (dfn[u] == low[u]){//u为该强连通分量中遍历所成树的根  缩点 
		++scc;
		do{
			v = S[--top];//栈中所有到u的点都属于该强连通分量,退栈

			vis[v] = false;
			belong[v] = scc;
		} while (u != v);
	}
}

int solve()
{

	scc = top = cnt = 0;

	memset(dfn, 0, sizeof(dfn));
	memset(vis, false, sizeof(vis));

	for (int u=1; u<=n; ++u)
		if (dfn[u] == 0)
			tarjan(u);

	return scc;
}



void CountDegree()
{

	memset(indeg, 0, sizeof(indeg));
	memset(outdeg, 0, sizeof(outdeg));

	for (int u=1; u<=n; ++u)
		for (int i=head[u]; i!=-1; i=Edge[i].next){
			int v = Edge[i].to;

			if (belong[u] != belong[v]){
				indeg[belong[v]]++;
				outdeg[belong[u]]++;
			}
		}
}

int main()
{

	int u, v, i;

	while (~scanf("%d", &n))

	{

		memset(cut, false, sizeof(cut));

		e = 0;

		memset(head, -1, sizeof(head));

		for(int i=1; i<=n; i++) {

			while(scanf("%d",&v) && v!=0) {
				addedge(i, v);
			}

		}
		int cutn = 0;
		int in = 0, out = 0;
			solve();

			if (scc == 1)
				printf("1\n0\n");
			else{
				CountDegree();

				in = 0, out = 0;

				for (int i=1; i<=scc; ++i){
					if (indeg[i] == 0)
						in++;
					if (outdeg[i] == 0)
						out++;
				}
			}
		if(scc != 1)
			printf("%d\n%d\n", in, (in > out ? in : out));
	}
	return 0;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值