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;
}
浙公网安备 33010602011771号