浅谈同构类问题的骗分算法

article/2025/4/30 22:34:01

ZLX算法-----同构类问题的有力骗分算法
前言:
ZLX算法是一种解决判定性同构问题的蒙特卡罗式骗分算法:总能在确定的运行时间内出解,但是得到的解不能保证正确。
尽管由于具有拓扑序,树同构和仙人掌同构存在多项式算法,但是图同构已经证明是NP问题,本文所述的是一种不能保证完全正确,但是正确概率很大的多项式算法(即伪多项式算法),与图同构是NP问题不冲突。
ZLX算法能保证两个图如果同构,一定输出YES,但是不能保证如果不同构,一定输出NO,ZLX算法的精髓就在于寻找不同构的证据,如果找不到,那么就认为同构。我们将证明,ZLX算法的正确性比较高,想要构造出一种卡掉ZLX算法的图是不太容易的,但是也能卡掉

原题链接:http://218.28.19.228/cogs/problem/problem.php?pid=2234

我们从一道例题开始讲起:
树木园:
给定两个仙人掌,判断是否同构。
仙人掌同构的定义:对其中一颗仙人掌进行重标号,如果重标号后两颗仙人掌相同,那么这两颗仙人掌同构。
算法一:

暴力匹配
时间复杂度O(Ann)(排列数),期望得分10分
算法二:
输出No,期望得分45分

算法三:随机输出Yes和No,期望得分50分,最高得分100分

算法四:输出Yes,期望得分55分
算法二三四在多组数据的情况下全部失效。
Hash算法系列:
我们需要用一些图论中与编号无关的东西来描述图的某个特征。


定理1:
图同构<->则图的所有与编号无关的特征相同.
证明:显然

定理2:
图的一些与编号无关的特征相同是图同构的必要条件,但不充分。
证明:显然

因此,我们hash的关键就在于选取有代表性的特征,且获得这些特征的时间复杂度在可容忍的范围内。
最容易想到的是用图中每个点的度数(与该点相邻的点的个数)来描绘图的特征,那么问题来了,计算度数后怎么进行匹配呢?
从小到大排序!

定理3:
图同构->两个图点的度数分别排序后完全匹配
证明:我们把图的信息压缩在了点上,排序就相当于对图进行重编号,而且重编号的点必须度数相同,于是我们就可以得到一个不保证正确的算法:

算法五:分别计算两个图所有点的度数,然后排序判断序列是否相等。
期望得分:80分(出题人数据太水啦)

我们不妨把排序后的度数称为度数序
很容易就能构造出度数序相同,但是图不同构的图,因为度数只能储存某个点到相邻点的边信息,而这个点跟比较远的点的关系难以被储存
我举一个简单易懂的例子:
 

我们把六边形的顶点和CH3看成图论中的点,这三个图的度数序相同(不与CH3相连的顶点度数为2,与CH3相连的顶点度数为3,2个CH3的顶点度数为1),但是他们结构不同,由此看来,我们需要更强有力的算法来辨别出这些图的结构.

怎样才能表示更精确的信息呢?
度数叠加!
我们再次计算某个点的邻接点的一层度数的和作为某个点的二层度数,然后重新得出一个序列
 
为什么叠加一层就能辨别出来对二甲苯和邻二甲苯呢?
因为我们把某个点邻接点的邻接点的信息传到了这个点!某个点的邻接点的一层度数包含了邻接点的邻接点的信息,我们通过一层叠加,就把这个信息传到了这个点。

我们计算某个点的邻接点的二层度数的和作为某个点的三层度数
这样,某个点邻接点的邻接点的邻接点的信息就传到了这个点.
我们计算某个点的邻接点的三层度数的和作为某个点的四层度数
……
我们计算某个点的邻接点的M-1层度数的和作为某个点的M层度数
这样,我们就把更多的度数信息压缩在了这个点.


定理4:A点的信息最先被传到B点的时间(需要叠加的层数)规模为dis(a,b)((a,b)的最短路径)
证明:这个可以通过自己意淫
定理5:点数为n的简单无向图(路径长度全为1)的不重复的最长的最短路径(图的直径?)至多为n
最坏的情况就是一条链,因此我们运行n次,每个点就一定会包含全图的度数信息,总时间复杂度为O(n*m),如果我们假设仅由度数信息就可判断是否同构,
就一定能保证正确。
但是,实际上叠加层数不需要很多,我就控制了20层左右就基本上能输出正解,
构造出20层以上仍然不能判断出来的图是不太容易的

以上的算法实际上通过上述性质利用了图的另一个信息:点与点之间的路径信息

剩下十分Wa在一颗小树和小仙人掌
是由于树和仙人掌的度数对结构的影响不如一般图明显,所以树和仙人掌需要更大的度数叠加
时间复杂度O(m*20),期望得分90分
策略一:树和仙人掌直接用特定的同构做
策略二:动态调整层数,如果N大层数就放小,如果N小层数就放大

期望得分100分

一些优化
空间优化:可以用滚动数组来叠加,防止M掉

Hash的优化:对多个大质数取模,或者变加法hash为乘法hash,异或和hash,或者把几种hash有机结合起来

扩展和优化

利用图的其他与标号无关的关键信息进行加强版的hash:每个双连通分量的大小,图的割顶,割桥,树的重心,仙人掌的某些点被套在大小为多少的环内,同样,我们为了快速传递整个图的信息,也可以对这些特征计算特征值然后用快速叠加算法优化正确率。

如果hash功能强,求有多少种重标号方式(即匹配方式)也许也是可以的。

如果你觉得本算法太难(其实本算法只难在信息传递的证明,且严格意义上来讲并不能被鄙视为一个骗分算法,因为其他算法也是hash啊!都有可能被卡啊),请看真·正解:

对于树,我们先找重心,然后以重心为根用有根树的hash,如果有多个重心,我们新建一个超级父亲指向这些重心即可

暴力可能有最小表示法

对于仙人掌上的每个环,我们新建一个红点连向环上所有的点,然后把原先环上的边全部删除。

出题人:这样就可以通过样例 2 辣! ……等等 那我为什么无法通过样例 3?

因为我们这样处理的时候忽略了环上的顺序!样例 3 就是这样的一个情况。

首先我们需要一种不支持交换律的哈希。(出题人:RK 啥的随便搞辣。。。 如果一个红点不是根节点,那么就从父亲节点沿着环的两个方向分别哈希一

遍,取较小值作为哈希值

代码量要5K+,5K+,还要考虑成吨的情况!

况且我这种算法是可以用来做一般图的!

虽然我说了一大堆不知所云的内容,代码是非常简单的:

#include <fstream>
#include <algorithm>
#include <queue>
#include <vector>
#define N 100010
using namespace std;
ifstream in("cactus.in");
ofstream out("cactus.out");
vector<int> F[N],G[N];
int n,m;
bool flag=1;//是否判定为同构
int mod=1000007;//可以对多个大质数取模
int M;
class node
{
public:int s[N];
}A[11],B[11];
bool operator <(node a,node b)
{for(int i=1;i<=n;i++)return a.s[i]<b.s[i];return 1;
}
void read()
{int i,u,v;in>>n>>m;for(i=1;i<=m;i++){in>>u>>v;G[u].push_back(v);G[v].push_back(u);A[1].s[u]++;A[1].s[v]++;}for(i=1;i<=m;i++){in>>u>>v;F[u].push_back(v);F[v].push_back(u);B[1].s[u]++;B[1].s[v]++;}//计算两个图的第一层度数(实为度数的二倍)M=min(1000,10000000/(n*20));M=max(M,10);//M为层数,动态调整层数
}
void work()
{int i,j,k,u,v;for(k=2;k<=M;k++){for(i=1;i<=n;i++){u=i;for(j=0;j<G[u].size();j++)//第二层由第一层转移,A[2]实为A[k],A[1]对应A[k-1],滚动数组优化节省空间
            {v=G[u][j];A[2].s[u]+=A[1].s[v];A[2].s[u]%=mod;}}for(i=1;i<=n;i++){u=i;for(j=0;j<F[u].size();j++){v=F[u][j];B[2].s[u]+=B[1].s[v];B[2].s[u]%=mod;}}A[1]=A[2];B[1]=B[2];sort(A[2].s,A[2].s+n+1);//对该层度数进行排序sort(B[2].s,B[2].s+n+1);for(i=1;i<=n;i++){if(A[2].s[i]!=B[2].s[i]){flag=0;//如果某个度数不对应,一定不同构break;}}for(i=1;i<=n;i++)A[2].s[i]=0;for(i=1;i<=n;i++)B[2].s[i]=0;if(!flag)break;}if(flag)out<<"YES"<<endl;else out<<"NO"<<endl;
}
int main()
{read();work();return 0;
}

 

转载于:https://www.cnblogs.com/Satoshi/p/5397032.html


http://chatgpt.dhexx.cn/article/Z2GoItcE.shtml

相关文章

win10下修改C盘用户文件夹名

之前安装一个程序出错&#xff0c;上网百度后是用户文件夹名为中文&#xff0c;也在网上找了好多方法&#xff0c;有同步的&#xff0c;有修改注册表的&#xff0c;最后我找到一个比较简单而且数据保留完整的方法。这种方法也会自动修改用户的环境变量&#xff0c;不过修改完后…

【Windows】Win10-更改c盘下的用户文件夹名

转载ooooohugh的文章&#xff0c;原文地址&#xff1a;https://blog.csdn.net/qq_33530388/article/details/71739845 当初 不小心用自己名字 作为计算机用户名&#xff0c;后来 许多软件因为 不支持 路径中有中文&#xff0c;导致吃了不少的亏&#xff0c;心疼。。。。 下面说…

Windows10更改c盘中用户名对应的文件名字

目录 前言一、修改步骤1.开启管理员账号并登陆2.重启电脑3.登录管理员账号4.重命名用户名对应的文件夹5.修改Path6.重启电脑并切换回你的账号7.修改环境变量8.重启电脑 二、修改导致的问题1.桌面大部分软件快捷方式失效2.部分软件无故消失 三、提醒Last 前言 强烈建议看完此文…

win10 修改c盘用户文件夹名称

c盘用户文件夹如果是中文名 可能会导致需要没必要的麻烦&#xff0c;记录一下修改方法 第一步&#xff1a;如果你电脑不是本地用户administrator&#xff0c;注销当前用户使用administrator登录 按winx 点击关机或注销 在点击注销 注销后如果没有Administrator登录方式&#…

有关windows10修改C盘用户中文名文件夹相关问题的具体解决方案

win10修改用户文件夹名 今天在下载安卓sdk开发工具的时候&#xff0c;安装出现了一个问题如图&#xff0c;左下角提示我们的sdk路径含有非ascll的字符&#xff0c;无法继续安装&#xff0c;其实不只是中文字符&#xff0c;英文字符中间若有空格也不能继续安装。 对于互联网学…

更改计算机用户文件夹,win10系统怎么自定义C盘用户文件夹名称

许多用户在安装win10系统之后&#xff0c;想要让电脑显得更加个性化&#xff0c;就想要给C盘中的用户文件夹名称进行自定义修改&#xff0c;那么win10系统怎么自定义C盘用户文件夹名称呢&#xff1f;接下来给大家分享一下具体的操作步骤。 1、在键盘上按下Windows键X 组合键&am…

Windows 11 的C盘User(用户)文件夹下的用户文件夹名称的修改

背景介绍&#xff1a;由于系统重装导致Windows 11的系统用户名与C盘User&#xff08;用户&#xff09;文件夹下的用户名文件夹&#xff08;公用文件夹旁边的文件夹&#xff09;出现名称不一致&#xff0c;事例中系统用户名命名为“寂萧”&#xff0c;User&#xff08;用户&…

win10怎么更改c盘用户计算机名,详解win10系统更改c盘用户名文件夹名称的设置技巧...

电脑一旦开机就会不停的运行&#xff0c;不可避免会出现软硬件问题&#xff0c;win10系统更改c盘用户名文件夹名称就是比较常见的状况&#xff0c;尤其是姑娘们遇到win10系统更改c盘用户名文件夹名称是要难过哭鼻子的&#xff0c;其实小编的经验是碰到win10系统更改c盘用户名文…

Windows 10系统中,如何重命名用户文件夹

免责声明 该方法不适用于所有情况&#xff0c;可能导致数据丢失、计算机无法重启等问题&#xff0c;请提前保护好数据&#xff01; 背景 许多Windows用户总是喜欢将文件放在用户文件夹&#xff08;C:\Users\username&#xff09;下&#xff0c;但有时候会发生一些令人苦恼的…

win10修改C盘用户文件夹下的文件命名

唉&#xff01;&#xff01;&#xff01;以前不太懂这些&#xff0c;取了个中文用户名。结果下载软件的过程中&#xff0c;各种出错&#xff0c;就是路径里面含有中文导致的。 这种情况下还都不能直接重命名&#xff0c;我试了各种方法&#xff0c;都不适合&#xff0c;最后找到…

windows修改用户文件夹名称 更改用户名 修改C盘Users目录下文件夹名称

知乎上的更详细版本 windows修改 C:\Users用户文件夹名称 把中文名修改为英文名 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/509804656 简短的说&#xff1a; 1 - 新建一个管理员账户A&#xff08;名称随意&#xff0c;不要和其他账户一样&#xff09;&#xff0c;注销…

win11修改C盘用户文件夹名称

新电脑使用microsoft账号进行初始化&#xff0c;导致用户文件夹名称是邮箱前五位&#xff0c;这个真的让人头痛。网上很多方法是直接改名称、改注册表信息等&#xff0c;导致出问题&#xff0c;结果要重装系统&#xff0c;很麻烦。 其实有一个很好的解决方法&#xff0c;如下&a…

如何修改C盘用户文件夹下的用户名

1、WindowsR&#xff0c;然后输入regedit&#xff0c;点击确定。 2、进入注册表编辑器后&#xff0c;依次打开HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\ProfileList。 3、打开ProfileList后&#xff0c;打开最后一项&#xff0c;然后在右侧找到Profile…

win10 重命名用户文件夹

背景 win10 修改系统用户名之后发现C:\Users下面的用户文件夹没有跟着改变, 于是手动调整一下 解决办法 操作前,先对重要的数据和配置做一下备份, 修改注册表 按Windows R组合键&#xff0c;打开运行对话框&#xff0c;输入regedit&#xff0c;打开注册表 接着找到路径计算…

window10如何重命名系统用户文件夹

此文章用于帮助重命名系统文件夹 有些软件在使用时会出现保存路径中不能有中文的情况&#xff0c;但又不便修改路径&#xff0c;而系统用户文件夹又是中文无法避开时想要重命名发现难以修改名字。这篇文章将详细介绍如何进行系统用户重命名。 1. 首先进入管理员账户&#xff…

更改C盘用户目录下的用户名(真实有效)

免责声明 以下所有操作均本人实测&#xff0c;目前本人无任何问题&#xff08;本人win11系统&#xff09;&#xff0c;如果出现任何问题与我无关。可能不同的电脑不同&#xff0c;所以请做好出现任何问题的心理准备&#xff0c;最好提前备份好重要文件&#xff01; 由于本人电…

关于重命名C盘User文件夹内用户名的心得

非必要千万不要改啊&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 写在前面&#xff1a;本文是对其他同主题博客的补充&#xff0c;仅供参考&#xff0c;只是希望能给大家提供帮助&#xff0c;请勿盲目根据本文所说操作进行&#xff0c;一定要结合实际情况&a…

更改C盘用户目录下的用户名(亲测有效)

免责声明 以下所有操作均来自别人&#xff0c;本人只负责实测&#xff0c;如果出现任何问题与我无关。可能不同的电脑有可能会出现一些问题&#xff0c;所以请做好出现任何问题的心理准备&#xff0c;最好提前备份好重要文件&#xff01;如果你准备好了&#xff0c;再去进行下…

修改Win10 C盘用户文件夹名称

修改Win10 C盘用户文件夹名称 1.注销当前用户2.登录另一个管理员账号3.修改C盘用户文件夹名4.修改注册表配置5.注销当前用户并登陆以修改的用户6.修改用户账户信息7.重启系统。 首先&#xff0c;你还需要有一个另外一个管理员用户&#xff0c;没有的话创建一个。 1.注销当前用…

C盘\用户目录下\管理员文件夹 如何重命名?

很多时候因为管理员文件夹名字是中文名&#xff0c;导致我们安装一些兼容性不好的软件出现异常&#xff0c;那么如何解决这个问题&#xff0c;把管理员文件夹进行重命名就OK了&#xff0c;具体操作如下 以上就是重命名管理员文件夹的完整教程了&#xff0c;这个过程会有2次重启…