[tarjan缩点 + 割点 / 割边 + 重边] 无向图求割点

[tarjan缩点 + 割点 / 割边 + 重边] 无向图求割点_第1张图片

#include 
#include 
#include 
#include 
#include 
#define ll long long
#define db double
using namespace std;

const int mn = 103;

int f[mn], ge[mn];

int ecnt, to[mn * mn], nx[mn * mn], fr[mn];
void addedge(int u, int v)
{
	++ecnt;
	to[ecnt] = v;
	nx[ecnt] = fr[u];
	fr[u] = ecnt;
}


/// Tarjan 模板
int idx, low[mn], dfn[mn];
bool insta[mn];
stack sta;
void tarjan(int u, int fa)
{
	int son = 0;	/// 求割点
	
	low[u] = dfn[u] = ++idx;
	sta.push(u);
	insta[u] = 1;
    bool fir = 1;    /// 带重边处理
	for (int i = fr[u]; i != -1; i = nx[i])
	{
		int v = to[i];
		if (v == fa && fir)	/// 无向图
		{
            fir = 0;
            continue;
        }
		if (!dfn[v])
		{
			/// 求割点
			son++;
			f[v] = u;
			///
			
			tarjan(v, u);
			low[u] = min(low[u], low[v]);
			
			/// 标记割点
			if (fa == 0 && son >= 2)
				ge[u] = 1;
			else if (fa != 0 && low[v] >= dfn[u])
				ge[u] = 1;
			///

            /// 求割边
			if (low[v] > dfn[u])
			{
				bridge++;
				cut[i] = 1;
				cut[i ^ 1] = 1; // (双向边 边标号从0开始)
			}
			/// 
		}
		if (dfn[v] && insta[v])
			low[u] = min(low[u], dfn[v]);
	}
	if (low[u] == dfn[u])
	{
		int v;
		do
		{
			v = sta.top();
			insta[v] = 0;
			sta.pop();
		}
		while (v != u);
	}
}
///

/// 去重边
map mp;
bool ishash(int u, int v)
{
	if (mp[u * mn + v] || mp[v * mn + u])
		return 1;
	mp[u * mn + v] = mp[v * mn + u] = 1;
	return 0;
}
///

void init()
{
	ecnt = 0, idx = 0;
	memset(f, 0, sizeof f);
	memset(ge, 0, sizeof ge);
	memset(fr, -1, sizeof fr);
	memset(dfn, 0, sizeof dfn);
	memset(low, 0, sizeof low);
	memset(insta, 0, sizeof insta);
	while (!sta.empty())
		sta.pop();
}

int main()
{
	int n;
	while (~scanf("%d", &n))
	{
		if (n == 0)
			break;
		
		init();
		
		int u;
		while (scanf("%d", &u))
		{
			if (u == 0)
				break;
			int v; char ch;
			while (1)
			{
				scanf("%d%c", &v, &ch);
                if (ishash(u, v))    // 去重边
                    continue;
				addedge(u, v);
				addedge(v, u);
				if (ch == '\n')
					break;
			}
		}
		
		tarjan(1, 0);
		
        /// 缩点后联通块间建树
        /*
		ecnt2 = 0;
		memset(fr2, -1, sizeof fr2);
		for (int i = 1; i <= n; i++)
		{
			for (int j = fr[i]; j != -1; j = nx[j])
			{
				int u = kuai[i], v = kuai[to[j]];
				if (u < v)	/// 去重
				{
					addedge2(u, v);	// 双向边
					addedge2(v, u);
				}
			}
		}
        */
		///

		int ans = 0;
		for (int i = 1; i <= n; i++)
		{
			if (ge[i])
				ans++;
		}
		
		printf("%d\n", ans);
	}
	return 0;
}

 

 

你可能感兴趣的:(模板,图论)