IOI2021集训队作业 226AE Maze Reduction

一个图,找出所有等价的点的集合。

等价的点即:两个点(A,B)分别开始走,每次可以选一条边走,可以分辨点的度数,可以知道来到一个点的前驱边是谁,能够分辨出连出去的边的顺时针顺序。如果没有办法分辨这两个点,这两个点就是等价的。

(nle 100)


哈希就能过了。。。

(f_{k,i,j})表示从点(i)开始先走第(j)条边进行探索,探索了(k)步的哈希值。

转移记下点前驱边开始(包括前驱边,如果不包括可能没有地方探索,导致全零的假象)顺时针转,形成的哈希值。

比较点(x)(y)时,将(f_{n,x})(f_{n,y})的最小表示法对比一下。

由于不会最小表示法,直接比较所有循环同构串哈希值的最小值,也能过。


using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#define N 105
#define ll long long
#define mo 998244353
#define jd 19260817
ll qpow(ll x,ll y){
	ll r=1;
	for (;y;y>>=1,x=x*x%mo)
		if (y&1)
			r=r*x%mo;
	return r;
}
int n;
int e[N][N],ne[N];
int re[N][N];
int f[N][N][N];
int vis[N];
int idc[N];
int minidc(int a[],int k){
	static int q[N*2];
	memcpy(q,a,sizeof(int)*k);
	memcpy(q+k,a,sizeof(int)*k);
	ll key=0,tmp=qpow(jd,k),res=INT_MAX;
	for (int i=0;i<k;++i)
		key=(key*jd+q[i])%mo;
	for (int i=k;i<k*2;++i){
		key=((key*jd+q[i])%mo-tmp*q[i-k]%mo+mo)%mo;
		res=min(res,key);
	}
	return res;
}
bool same(int x,int y){
	if (ne[x]!=ne[y]) return 0;
	return idc[x]==idc[y];
}
int main(){
	freopen("in.txt","r",stdin);
	scanf("%d",&n);
	for (int i=1;i<=n;++i){
		scanf("%d",&ne[i]);
		for (int j=0;j<ne[i];++j){
			scanf("%d",&e[i][j]);
			re[i][e[i][j]]=j;
		}
	}
	for (int i=1;i<=n;++i)
		for (int j=0;j<ne[i];++j)
			f[0][i][j]=ne[i];
	for (int k=1;k<=n;++k)
		for (int i=1;i<=n;++i)
			for (int j=0;j<ne[i];++j){
				int y=e[i][j];
				ll key=0;
				for (int t=re[y][i];t<ne[y];++t)
					key=(key*jd+f[k-1][y][t])%mo;
				for (int t=0;t<re[y][i];++t)
					key=(key*jd+f[k-1][y][t])%mo;
				f[k][i][j]=key;
			}
	for (int i=1;i<=n;++i)
		idc[i]=minidc(f[n][i],ne[i]);
//	for (int i=1;i<=n;++i){
//		printf("i=%d : %d
",i,idc[i]);
//		for (int j=0;j<ne[i];++j)
//			printf("%d ",f[n][i][j]);
//		printf("
");
//	}
	int bz=0;
	for (int i=1;i<=n;++i)
		if (!vis[i]){
			vis[i]=1;
			static int q[N];
			int k=1;
			q[1]=i;
			for (int j=i+1;j<=n;++j)
				if (!vis[j] && same(i,j)){
					vis[j]=1;
					q[++k]=j;
				}
			if (k>1){
				for (int j=1;j<=k;++j)
					printf("%d ",q[j]);
				printf("
");
				bz=1;
			}
		}
	if (bz==0)
		printf("none
");
	return 0;
}
原文地址:https://www.cnblogs.com/jz-597/p/13966386.html