首页 > 其他分享 >Waiting for Hack

Waiting for Hack

时间:2023-03-01 12:23:35浏览次数:49  
标签:dld int ed fsl next dep Waiting Hack

无向图最小环(边权为1)

现在给一张 \(n\) 个点 \(m\) 条边的无向图,求图中最小环的长度。

很久以前就想过类似的问题,但是一直犯懒没打。
无复杂度保证,只是本彩笔卡不掉而已

只考虑没有重边自环的情况。

我们重复进行以下操作:

  1. 拓扑排序。将度为 \(1\) 的点删掉,然后更新其他节点的度,直到所有的点的度都 $ > 1$ 为止。

  2. 选择一个 度最大 的点,以这个点为起点跑 BFS,找最小环,更新答案。然后把这个节点删掉。

如果所有点都被删掉了就结束。

正确性显然,但是需要注意几个细节:

  1. 使用桶来维护度。由于度单调不增,直接开桶从大往小扫就行。
    至于为什么不能每次扫所有点找度最大,可以往下看。

  2. BFS。若以 \(a\) 为起点找环,则可以将 \(a\) 的所有相邻节点染上不同的颜色。
    如果在 BFS 更新最短路的时候发现两个不同颜色的点更新了同一个点则发现了最小环。
    当然,如果发现以 \(a\) 为起点无法找到比之前更小的环,那就当做找到了,没必要接着找了。
    在找到最小环之后应该立即退出以确保复杂度

  3. 找环前不要全局 memset。此算法的复杂度基于每次 BFS 不会跑满,所以跑了多少就清空多少。
    一种比较方便的实现是用数组模拟队列,最后重新扫一遍队列即可。

  4. 关于删边。显然我们在删掉一个点之后需要把与其相邻的边也删掉。
    可以使用前向星存图,延迟删除,然后给删了的点打标记。如果访问到了再把这条边删了。

以及,如果图是随机生成的,大概率答案为 \(3\)。当现有的答案已经为 \(3\) 时我们可以直接退出。
不会影响复杂度,但是随机数据下确实会优化不少。

简洁的代码实现就放下面了,心情好的话就 \(hack\) 一下吧。

A Big Tuo of Shit
#include <vector>
#include <stdio.h>
#define sz 100005
using namespace std;
const int inf = 0x3f3f3f3f;
struct site
{
	int ed, next;
};
site dld[sz << 1];
int n, m, now, mx, toans;
bool del[sz];
int fsl[sz], ds[sz], dep[sz], col[sz], que[sz];
vector<int> ts[sz];
int read();
void net(int, int);
void del_p(int);
int sol();
void dfs();
int geta();
int bfs(int);
int main()
{
	int x, y;
	n = read(); m = read();
	for (int i = 1; i <= m; ++i)
	{
		x = read(); y = read();
		net(x, y); net(y, x);
	}
	for (int i = 1; i <= n; ++i)
	{
		mx = max(mx, ds[i]);
		ts[ds[i]].emplace_back(i);
	}
	printf ("%d\n", sol());
	return 0;
}

int read()
{
	int x = 0;
	char c = getchar();
	while (c < '0') c = getchar();
	do {
		x = x * 10 + (c & 15);
		c = getchar();
	}while (c >= '0');
	return x;
}

void net(int a, int b)
{
	++ds[b];
	dld[++now].ed = b;
	dld[now].next = fsl[a];
	fsl[a] = now;
}

void del_p(int x)
{
	ds[x] = 0;
	del[x] = true;
	for (int i = fsl[x]; i; i = dld[i].next)
		if (!del[dld[i].ed])
		{
			--ds[dld[i].ed];
			ts[ds[dld[i].ed]].emplace_back(dld[i].ed);
		}
}

int sol()
{
	toans = inf;
	int x;
	while (1)
	{
		dfs();
		x = geta();
		if (x == -1)
			break;
		toans = min(toans, bfs(x));
		if (toans <= 3)
			break;
		del_p(x);
	}
	return toans == inf ? -1 : toans;
}

void dfs()
{
	int x;
	while (ts[1].size() + ts[0].size())
		for (int i = 0; i < 2; ++i)
			while (ts[i].size())
			{
				x = ts[i].back();
				ts[i].pop_back();
				if (!del[x])
					del_p(x);
			}
}

int geta()
{
	int x;
	while (mx)
	{
		while (ts[mx].size())
		{
			x = ts[mx].back();
			ts[mx].pop_back();
			if (ds[x] == mx)
				return x;
		}
		--mx;
	}
	return -1;
}

int bfs(int a)
{
	int lf = 1, rt = 0, x, ans = inf, mn;
	while (del[dld[fsl[a]].ed])
		fsl[a] = dld[fsl[a]].next;
	for (int i = fsl[a], last = 0; i; last = i, i = dld[i].next)
		if (del[dld[i].ed])
		{
			dld[last].next = dld[i].next;
			i = last;
		}else
		{
			que[++rt] = dld[i].ed;
			dep[dld[i].ed] = 1;
			col[dld[i].ed] = rt;
		}
	while (rt >= lf)
	{
		x = que[lf++];
		if ((dep[x] << 1) >= toans || (ans != inf && dep[x] > mn))
			break;
		while (fsl[x] && del[dld[fsl[x]].ed])
			fsl[x] = dld[fsl[x]].next;
		for (int i = fsl[x], last = 0; i; last = i, i = dld[i].next)
			if (dld[i].ed != a)
			{
				if (del[dld[i].ed])
				{
					dld[last].next = dld[i].next;
					i = last;
				}else if (!dep[dld[i].ed])
				{
					dep[dld[i].ed] = dep[x] + 1;
					que[++rt] = dld[i].ed;
					col[dld[i].ed] = col[x];
				}else if (col[dld[i].ed] != col[x])
				{
					ans = min(ans, dep[x] + dep[dld[i].ed] + 1);
					mn = dep[x];
					break;
				}
			}
	}
	for (int i = 1; i <= rt; ++i)
		dep[que[i]] = 0;
	for (int i = 1; i <= rt; ++i)
		col[que[i]] = 0;
	return ans;
}

标签:dld,int,ed,fsl,next,dep,Waiting,Hack
From: https://www.cnblogs.com/Sakura-Lu/p/17167732.html

相关文章

  • Redis Cluster部署一直卡在Waiting for the cluster to join ......
    1、问题现象 线上部署一个40分片的RedisCluster集群,初始化的时候日志输出一直是Waitingfortheclustertojoin......(大集群初始化的时候会出现时间长)2、问题分析......
  • 华硕 TUF GAMING FX504GE_FX80GE电脑 Hackintosh 黑苹果efi引导文件
    硬件型号驱动情况主板华硕FX504GE(HM370芯片组)处理器英特尔Corei5-8300H@2.30GHz四核已驱动内存16GBLPDDR4X3200MHz已驱动硬盘金士顿512G已驱动显卡IntelUHD630+N......
  • css hack
    一、CSS hack是什么?CSS hack是通过在css样式中加入一些特殊的符号,让不同的浏览器识别不同的符号(不同的浏览器识别的符号是有不同的标准的,CSShack就是让我们记住这个标......
  • OSCP考试Hackthebox靶机推荐
    Pain:Pain是一台基于Linux的靶机,难度级别为中等,涵盖了许多常见的漏洞类型和渗透测试技术。这台靶机需要进行横向渗透,涉及到一些密码破解和提权技术。Legacy:Legacy是一......
  • Lenovo Legion Y530-15ICH电脑 Hackintosh 黑苹果efi引导文件
    原文来源于黑果魏叔官网,转载需注明出处。硬件型号驱动情况主板LenovoLegionY530-15ICH处理器Intel®Core™i7-8750H(Coffee-Lake)已驱动内存16GBRAMDDR42667MHz已驱......
  • 戴尔Latitude 3410电脑 Hackintosh 黑苹果efi引导文件
    原文来源于黑果魏叔官网,转载需注明出处。硬件型号驱动情况主板戴尔Latitude3410处理器英特尔酷睿i7-10510U已驱动内存8GB已驱动硬盘SKhynixBC511NVMeSSD已驱动显卡Inte......
  • 联想Thinkpad X1 Carbon (7th Gen)电脑 Hackintosh 黑苹果efi引导文件
    原文来源于黑果魏叔官网,转载需注明出处。硬件型号驱动情况主板ThinkpadX1Carbon处理器IntelCorei5-10210U(formerlyCometLake)已驱动内存8GBDDR3(orsomethinglik......
  • 黑苹果Hackintosh 修复磁盘 NVMe 磁盘的错误问题
    原文来源于黑果魏叔官网,转载需注明出处。错误信息macOS的问题报告系统登录后报错信息如下:panic(cpu0caller0xffffff7f83e24231):nvme:"Fatalerroroccurred.CSTS=0x......
  • CSS Hack
    一、什么是CSSHackCSShack是通过CSS样式中加入一些特殊的符号,让不同的浏览器识别不同的符号(什么样的浏览器识别什么样的符号是有标准的,CSShack就是让你记住这个标准),以......
  • 联想小新 Air-14 2019IML电脑 Hackintosh 黑苹果efi引导文件
    原文来源于黑果魏叔官网,转载需注明出处。硬件型号驱动情况主板LenovoLNVNB161216处理器IntelCorei5-10210U/i7-10510U已驱动内存8GBDDR42666已驱动硬盘康佳KAK0500B1......