您的位置:首页 > 其它

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

2011-01-20 22:36 309 查看
刚看了强连通分量,找来些题练练。发现强连通不会赤裸裸地考,会结合一些其它知识。

这题做得比较曲折,一开始没有强连通,对反向图的每个点进行一次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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: