• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

  • 联系
  • 订阅
  • 管理

View Post

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;
}

posted on 2011-01-20 22:36  sysuwhj  阅读(728)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3