为什么TLE?
查看原帖
为什么TLE?
1252898
ShadowBlood楼主2024/4/4 15:54
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

//链式前向星、割点(dfs)、堆

#define N 20005
#define MIN(a, b) a < b ? a : b

struct line
{
	int nex;
	int end;
} edge[200005];//无向图双倍
int fat[N] = { 0 };
int dn = 0;//当前时间戳
int dfn[N] = { 0 };//时间戳
int low[N] = { 0 };//不经过父节点能到最小时间戳的节点
bool flag[N] = { 0 };//是否为割点
int ans = 0;//割点数量

int read()
{
	int num = 0;
	char ch = getchar();

	while (ch < 48 || 57 < ch) ch = getchar();

	while (48 <= ch && ch <= 57)
	{
		num = num * 10 + ch - 48;
		ch = getchar();
	}

	return num;
}

void add_edge(const int* hea, const int* end)
{
	static int i = 0;//编号

	edge[++i].end = *end;
	edge[i].nex = fat[*hea];
	fat[*hea] = i;//更新编号
}

void Tarjan(int id, int* root)//当前节点、该树根节点
{
	dfn[id] = low[id] = ++dn;//初始化
	int son_tree = 0;//子树个数

	//遍历所有直接相连的边
	for (int i = fat[id]; i; i = edge[i].nex)
	{
		int end = edge[i].end;
		if (dfn[end] == 0)//还未搜索
		{
			son_tree++;//记录
			Tarjan(end, root);//搜索
			low[id] = MIN(low[id], low[end]);//更新不经过父节点能到最小时间戳的节点

			if (low[end] >= dfn[id] && flag[id] == 0 && id != *root)//非根节点的点是否为割点
			{
				ans++, flag[id] = 1;//记录
			}
		}
		else
		{
			low[id] = MIN(low[id], dfn[end]);
		}
	}

	if (id == *root && flag[id] == 0 && son_tree >= 2)
    	{
     	 ans++, flag[id] = 1;//特判根节点
   	 }
}

void write(int num)
{
	if (num > 9) write(num / 10);
	putchar(num % 10 + 48);
}

int main()
{
	int n = read(), m = read();//点、边数

	for (int i = 1; i <= m; i++)//连接情况
	{
		int x = read(), y = read();

		add_edge(&x, &y), add_edge(&y, &x);//加边
	}

	for (int i = 1; i <= m; i++)//Tarjan
	{
		if (dfn[i] == 0)//是否已经搜索过
		{
			Tarjan(i, &i);
		}
	}

	write(ans);//快写 - 割点个数
	putchar(10);
	for (int i = 1; i <= n; i++)//编号从小到大输出割点
	{
		if (flag[i])
     	 	{
      	  		write(i), putchar(32);
      		}
	}

	return 0;
}

其实我不太理解的说,求讲解!

2024/4/4 15:54
加载中...