hdu 3639 Hawk-and-Chicken 强连通分支

        刚看了强连通分量,找来些题练练。发现强连通不会赤裸裸地考,会结合一些其它知识。

        这题做得比较曲折,一开始没有强连通,对反向图的每个点进行一次dfs, 发现超时,后来用了强连通,弄了很久才弄出。

        解题思路:先把强连通分支压缩成一个点,再组成一个有向无环反向图, 对每个入度为0的点进行dfs, 找出最大的值即可。注意到,答案只能是在反向图入度为0 的点中。

#include <iostream>

#include <vector>

using namespace std;



const int MAX = 5005;



bool isvisit[MAX];



vector<int> GT[MAX];

vector<int> G[MAX];

vector<int> arcs[MAX];

int n, m;

int scc_v[MAX];

int cnt, total, scc, time;

int f[MAX];

int id[MAX];

int ingree[MAX];

int ans[MAX];





void dfs(int v)

{

	isvisit[v] = true;

	

	for (int i = 0; i < G[v].size(); i++)

		if (!isvisit[G[v][i]])

			dfs(G[v][i]);



	f[cnt++] = v;

}



void dfs2(int v)

{

	id[v] = scc;

	isvisit[v] = true;

	time++;

	for (int i = 0; i < GT[v].size(); i++)

		if ( !isvisit[GT[v][i]])	

			dfs2(GT[v][i]);	

}



void SCC()

{

	memset(isvisit, false, sizeof(isvisit));	

	cnt = 0;

	for (int i = 0; i < n; i++)	

		if (!isvisit[i])		

			dfs(i);



	memset(isvisit, false, sizeof(isvisit));

	scc = 0;

	for (int i = cnt-1; i >= 0; i--)

	{

		if (!isvisit[f[i]])

		{

			time = 0;

			dfs2(f[i]);

			scc_v[scc++] = time; //记录每一个强连通分支的顶点个数

		}

	}

}



void dfs3(int v)

{

	isvisit[v] = true;

	total += scc_v[v];

	for (int i = 0; i < arcs[v].size(); i++)

		if (!isvisit[arcs[v][i]])

			dfs3(arcs[v][i]);

}



int main()

{

	int cases;

	int a, b;

	

	cin >> cases;



	for (int k = 0; k < cases; k++)

	{

		scanf("%d%d", &n, &m);



		for (int i = 0; i < n; i++)

		{

			G[i].clear();

			GT[i].clear();

			arcs[i].clear();

		}



		for (int i = 0; i < m; i++)

		{

			scanf("%d%d", &a, &b);

			G[a].push_back(b);

			GT[b].push_back(a);

		}



		SCC(); //求强连通分量



		memset(ingree, 0, sizeof(ingree));



		//创建新的强连通分量的反向图

		for (int i = 0; i < n; i++)

			for (int j = 0; j < G[i].size(); j++)

				if (id[i] != id[G[i][j]])

				{

					arcs[id[G[i][j]]].push_back(id[i]);

					ingree[id[i]]++;

				}



		int maximum = -1;

		maximum = -1;

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



		//搜索入度为0的顶点

		for (int i = 0; i < scc; i++)

			if (ingree[i] == 0)

			{

				total = 0;

				memset(isvisit, false, sizeof(isvisit));

				dfs3(i);

				ans[i] = total;

				maximum = max(maximum, ans[i]);

			}

		

		int i;

		cout << "Case " << k+1 << ": " << maximum - 1<< endl;

		for (i = 0; i < n; i++)

			if ( ans[id[i]] == maximum)

			{

				printf("%d", i);

				break;

			}

		

		for (i++; i < n; i++)

			if ( ans[id[i]] == maximum)		

				printf(" %d", i);



		printf("\n");		

	}

	return 0;

}

你可能感兴趣的:(awk)