POJ1236(tarjan入門)

題意:有n所學校需要信息交流,每個學校有一個信息下發列表,表示這個學校可以把信息傳遞給列表裏的學校,問開始至少需要幾個學校發出信息才能使所以學校都接收信息,如果不能完成問最少要往信息列表裏添加多少條信息

第一問就是縮點然後求入度爲0的點的個數, 第二問相當於求補多少條邊能使整個圖聯通, 補的邊數是入度爲0和出度爲0的點數中大的那個(挺好理解的就不解釋了)

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;
const int mx = 105;
int dfn[mx], low[mx], stack[mx], color[mx], in[mx], out[mx], n, cnt, top, sum;
bool vis[mx];
vector <int> G[mx];

void init()
{
	cnt = sum = top = 0;
	memset(vis, false, sizeof(vis));
	memset(dfn, 0, sizeof(dfn));
	memset(low, 0, sizeof(low));
	memset(in, 0, sizeof(in));
	memset(out, 0, sizeof(out));
	for (int i = 0; i < mx; i++)
		G[i].clear();
}

void tarjan(int u)
{
	low[u] = dfn[u] = ++cnt;
	stack[++top] = u;
	vis[u] = true;
	int v, len = G[u].size();
	
	for (int i = 0; i < len; i++)
	{
		v = G[u][i];
		if (!dfn[v])
		{
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if (vis[v])
			low[u] = min(low[u], dfn[v]);
	}
	if (low[u] == dfn[u])
	{
		color[u] = ++sum;
		//printf("sum = %d\n",sum);
		while (stack[top] != u)
		{
			//printf("top = %d\n",stack[top]);
			vis[stack[top]] = false;
			color[stack[top]] = sum;
			top--;
		}
		//printf("top = %d\n",u);
		vis[u] = false;
		top--;
	}
}

void solve()
{
	for (int i = 1; i <= n; i++)
		if (!dfn[i]) tarjan(i);
	int v;
	for (int i = 1; i <= n; i++)
	{
		int len = G[i].size();
		for (int j = 0; j < len; j++)
		{
			v = G[i][j]; 
			if (color[i] != color[v])
			{
				out[color[i]]++;
				in[color[v]]++;
			}
		}
	}
}

int main()
{
	while (scanf("%d",&n) != EOF)
	{
		init();
		for (int i = 1; i <= n; i++)
		{
			int x;
			while (scanf("%d",&x) == 1 && x != 0)
				G[i].push_back(x);
		}
		solve();
		if (sum == 1)
		{
			printf("1\n0\n");
			continue;
		}
		int ans1 = 0, ans2 = 0;
		for (int i = 1; i <= sum; i++)
		{
			if (in[i] == 0) ans1++;
			if (out[i] == 0) ans2++;
		}
		printf("%d\n%d\n",ans1,max(ans1,ans2));
	}
	
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章