• POI2001 跳舞蝇的教练


    题目

    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来解决。

    下面将问题拆分:

    1. 一棵树的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;
    }
    
    1. 一个基环树将环拆了之后,可以知道每个树的hash值,然后爆扫断环的起点,将取最终得到的树的hash值最小的那个。
    2. 将所有基环树的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;
    }
    
  • 相关阅读:
    【SpringBoot】SpringBoot中请求路径问题
    CodeForces
    CodeForces
    7-36 旅游规划 (25 分(Dijkstra)
    CodeForces
    CodeForces
    CodeForces
    CodeForces
    CodeForces
    CodeForces
  • 原文地址:https://www.cnblogs.com/zryabc/p/11202133.html
Copyright © 2020-2023  润新知