题目
Byteland一直以奇妙的跳舞蝇而闻名于世。驯养的苍蝇能和着音乐的节奏精确地做每一次飞跃。通常,训练者会在
桌上放一排硬币,这些硬币的排列并不按照特定的顺序。每枚硬币上都有一行题字:i→j,i是这枚硬币的编号,j
是站在硬币i上的苍蝇下一步应该飞往的硬币编号。训练者在每个硬币上放一只苍蝇,然后开始放音乐。那些苍蝇
就跟着音乐的节拍开始跳舞,在每一拍中苍蝇都会直接跳到编号为j的硬币上。在舞蹈中,可能会出现多只苍蝇在
同一硬币上的情况。这样,跳舞蝇就会一起继续表演。假定有n只苍蝇,n枚硬币。则一旦确定了n枚硬币上的题字
,那么这场表演也就确定了。然而,对硬币不同的设置也可能导致相同的表演,只要我们把硬币按适当的顺序排列
让我们先来看3枚硬币上的表演。
如果表演是这样进行:
从第一个硬币到第二个,第二个到第三个,第三个又回到第一个硬币(表示为1→2,2→3,3→1)。
具体表演是3只苍蝇绕圈跳跃,从不相遇。那么表演1→2,2→3,3→3,则是与其不同的。
因为该表演为:两拍后,所有的苍蝇在第3枚硬币上相遇,然后一直在原地跳跃。
但是,设置1→2,2→3,3→2,4→4和1→1、2→3、3→2、4→3就是同样的类型。
如果你把前者的硬币从左到右排列,而把后者从右到左排列,就会看到相同的表演。
任务:
如果跳舞蝇的两次表演是相同的,就会使观众不满,请编写一个程序:
读入测试任务的个数;
对每一个测试任务,从PCH.IN中读入两组硬币设置,验证是否能把硬币按一定顺序排列,使跳舞蝇给出相同的表演;
思路
建立模型很重要。
首先这是一个有向图组成的森林。
由于每条边的出度都为1,所以这实际上是由基环树组成的森林。题目的意思就是要比较两个基环树森林是否一致。
对于这种问题,一般都借助于hash来解决。
下面将问题拆分:
- 一棵树的hash可以借助以下代码实现:每个点向上跳的时候将其携带的信息放到父亲节点上。
int get_hash(int x,int f){
int res=1;
for(int i=h[x];i;i=G[i].nxt){
int u=G[i].to;
if(u==f||vis[u])continue;
res=(res+1LL*get_hash(u,x)*base%mod)%mod;
}
return res;
}
- 一个基环树将环拆了之后,可以知道每个树的hash值,然后爆扫断环的起点,将取最终得到的树的hash值最小的那个。
- 将所有基环树的hash值排序,从小到大再进行一次hash
这样就实现了,相同的森林得到的hash值相同的效果。
ps:此题数据巨水
代码
#include<bits/stdc++.h>
#define M 10005
#define clr(x,y) memset(x,y,sizeof(x))
using namespace std;
const int base=233;
const int mod=1e9+7;
int d,n;
int h[M],tt;
struct edge{
int nxt,to;
}G[M<<1];
void Add(int a,int b){
G[++tt]=(edge){h[a],b};
h[a]=tt;
}
int stk[M],top;
bool vis[M],mark[M];
int A[M],Pow[M];
bool dfs_lop(int x,int f){
if(vis[x])return 1;
vis[x]=mark[x]=1;
stk[++top]=x;
for(int i=h[x];i;i=G[i].nxt){
int u=G[i].to;
if(u==f)continue;
if(dfs_lop(u,x))return 1;
}
top--;vis[x]=0;
return 0;
}
int get_hash(int x,int f){
int res=1;
for(int i=h[x];i;i=G[i].nxt){
int u=G[i].to;
if(u==f||vis[u])continue;
res=(res+1LL*get_hash(u,x)*base%mod)%mod;
}
return res;
}
int QQ[M],Qcnt;
int hav[M],hcnt;
int get_has(){
Qcnt=0;clr(vis,0);clr(mark,0);
hcnt=0;
for(int i=1;i<=n;i++){
if(!mark[i]){
top=0;
if(dfs_lop(i,0))hav[++hcnt]=i;
}
}
clr(mark,0);
for(int j=1;j<=hcnt;j++){
top=0;
dfs_lop(hav[j],0);
for(int i=1;i<=top;i++)A[i]=get_hash(stk[i],0);
int mi=2e9,res=0;
for(int i=1;i<=top;i++)res=(1LL*res*base+A[i])%mod;mi=res;
for(int i=2;i<=top;i++){
res=((res-1LL*A[i-1]*Pow[top-1]%mod)%mod+mod)%mod;
res=(1LL*res*base+A[i-1])%mod;
mi=min(res,mi);
}
QQ[++Qcnt]=mi;
}
for(int i=1;i<=n;i++){
if(!mark[i]){
QQ[++Qcnt]=get_hash(i,0);
}
}
sort(QQ+1,QQ+Qcnt+1);
int res=0;
for(int i=1;i<=Qcnt;i++)
res=(1LL*res*base%mod+QQ[i])%mod;
return res;
}
int main(){
Pow[0]=1;
for(int i=1;i<=2000;i++)Pow[i]=1LL*base*Pow[i-1]%mod;
scanf("%d",&d);
while(d--){
scanf("%d",&n);
clr(h,0);tt=0;
for(int i=1,x;i<=n;i++)scanf("%d",&x),Add(x,i);
int a=get_has();
clr(h,0);tt=0;
for(int i=1,x;i<=n;i++)scanf("%d",&x),Add(x,i);
int b=get_has();
if(a==b)puts("T");
else puts("N");
}
return 0;
}