IOI2021集训队作业 226AE Maze Reduction

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

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

\(n\le 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\n",i,idc[i]);
//		for (int j=0;j<ne[i];++j)
//			printf("%d ",f[n][i][j]);
//		printf("\n");
//	}
	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("\n");
				bz=1;
			}
		}
	if (bz==0)
		printf("none\n");
	return 0;
}
posted @ 2020-11-12 21:34  jz_597  阅读(138)  评论(0编辑  收藏  举报