zoukankan      html  css  js  c++  java
  • CF762F Tree nesting

    题目连接

    问题分析

    可以给小树钦定一个根, (Dp[i][j]) 表示大树上的点 (i) 对应到小树上的点 (j) 的可能的方案数。然后每一步转移都是一个状压DP(将小树是否被匹配状压,然后枚举大树上的点和小树上的点匹配)。

    但如果这样统计的话,在两种情况下有重复:

    • 在小树取不同的根但仍同构;
    • 确定小树的根后,小树的子树同构。

    所以我们对钦定根后的小树进行哈希,即可排除第一种重复。而如果小树的某两个子树同构,那么就在统计的时候强行钦定一个顺序,这样就解决了第二种重复。

    参考程序

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <set>
     
    const int Maxn = 2000;
    const int Maxm = 12;
    const int MaxAlpha = 1 << Maxm;
    int Mod = 1e9 + 7;
    struct edge
    {
        int To, Next;
        edge() {}
        edge(int _To, int _Next) : To(_To), Next(_Next) {}
    };
    struct node {
        int Value, Index;
        node() {}
        node(int _Value, int _Index) : Value(_Value), Index(_Index) {}
        inline bool operator<(const node Other) const
        {
            return Value < Other.Value;
        }
    };
    edge Edge1[Maxn << 1], Edge2[Maxm << 1];
    int n, m, Ans;
    int Start1[Maxn + 1], Start2[Maxm + 1], Used1, Used2;
    int Hash[Maxm + 1], Father[Maxm + 1], Size[Maxm + 1];
    int Dp[Maxn + 1][Maxm + 1], F[2][MaxAlpha];
    node Temp[Maxm + 1]; int Ctrl[Maxm + 1];
    std::set<int> Set;
     
    inline void AddEdge1(int x, int y);
    inline void AddEdge2(int x, int y);
    inline void Init();
    void GetHash(int u, int Fa);
    void Calc(int u, int Fa);
     
    int main()
    {
        Init();
        for (int i = 1; i <= m; ++i)
        {
            GetHash(i, 0);
            if (Set.count(Hash[i]))
                continue;
            Set.insert(Hash[i]);
            memset(Dp, 0, sizeof(Dp));
            Calc(1, 0);
            for (int j = 1; j <= n; ++j)
                Ans = (Ans + Dp[j][i]) % Mod;
        }
        printf("%d
    ", Ans);
        return 0;
    }
     
    inline void AddEdge1(int x, int y)
    {
        Edge1[++Used1] = edge(y, Start1[x]);
        Start1[x] = Used1;
        return;
    }
     
    inline void AddEdge2(int x, int y)
    {
        Edge2[++Used2] = edge(y, Start2[x]);
        Start2[x] = Used2;
        return;
    }
     
    inline void Init()
    {
        scanf("%d", &n);
        for (int i = 1; i < n; ++i)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            AddEdge1(x, y);
            AddEdge1(y, x);
        }
        scanf("%d", &m);
        for (int i = 1; i < m; ++i)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            AddEdge2(x, y);
            AddEdge2(y, x);
        }
        return;
    }
     
    void GetHash(int u, int Fa)
    {
        Size[u] = 1;
        Father[u] = Fa;
        for (int t = Start2[u]; t; t = Edge2[t].Next)
        {
            int v = Edge2[t].To;
            if (v == Fa)
                continue;
            GetHash(v, u);
            Size[u] += Size[v];
        }
        int Count = 0;
        for (int t = Start2[u]; t; t = Edge2[t].Next)
        {
            int v = Edge2[t].To;
            if (v == Fa)
                continue;
            Temp[++Count] = node(Hash[v], v);
        }
        std::sort(Temp + 1, Temp + Count + 1);
        Hash[u] = 0;
        for (int i = 1; i <= Count; ++i)
        {
            Hash[u] <<= Size[Temp[i].Index] << 1;
            Hash[u] += Hash[Temp[i].Index];
        }
        Hash[u] <<= 1;
        Hash[u] += 1 << ((Size[u] << 1) - 1);
        return;
    }
     
    void Calc(int u, int Fa)
    {
        for (int t = Start1[u]; t; t = Edge1[t].Next)
        {
            int v = Edge1[t].To;
            if (v == Fa) 
                continue;
            Calc(v, u);
        }
        for (int uu = 1; uu <= m; ++uu)
        {
            if (Size[uu] == 1)
            {
                Dp[u][uu] = 1;
                continue;
            }
            int Count = 0;
            memset(Ctrl, 0, sizeof(Ctrl));
            for (int t = Start2[uu]; t; t = Edge2[t].Next)
            {
                int v = Edge2[t].To;
                if (v ==Father[uu]) continue;
                Temp[++Count] = node(Hash[v], v);
            }
            std::sort(Temp + 1, Temp + Count + 1);
            for (int i = 2; i <= Count; ++i)
                if (Temp[i].Value == Temp[i - 1].Value)
                    Ctrl[i] = 1;
            memset(F, 0, sizeof(F));
            F[0][0] = 1;
            int Step = 0;
            for (int t = Start1[u]; t; t = Edge1[t].Next)
            {
                int v = Edge1[t].To;
                if (v ==Fa)
                    continue;
                for (int j = 0; j < 1 << Count; ++j)
                    F[(Step + 1) & 1][j] = 0;
                for (int j = 0; j < 1 << Count; ++j)
                    for (int k = 1; k <= Count; ++k)
                    {
                        if ((j >> (k - 1)) & 1)
                            continue;
                        if (Ctrl[k] && ((j >> (k - 2)) & 1) == 0)
                            continue;
                        F[(Step + 1) & 1][j | (1 << (k - 1))] += 1LL * F[Step & 1][j] * Dp[v][Temp[k].Index] % Mod;
                        F[(Step + 1) & 1][j | (1 << (k - 1))] %= Mod;
                    }
                for (int j = 0; j < 1 << Count; ++j)
                {
                    F[(Step + 1) & 1][j] += F[Step & 1][j];
                    F[(Step + 1) & 1][j] %= Mod;
                }
                ++Step;
            }
            Dp[u][uu] = F[Step & 1][(1 << Count) - 1];
        }
        return;
    }
    
    
  • 相关阅读:
    Mybatis集成dbcp-java.lang.AbstractMethodError: Method org/apache/commons/dbcp/DelegatingResultSet.isClosed()Z is abstract
    Word 错误提示“此功能看似已中断,并需要修复” 解决
    解决 org.springframework.context.annotation.ConflictingBeanDefinitionException
    IDEA中的JAVA WEB项目启动报错的定位方法
    Oracle数据库中包含CLOB字段表的导出和导入
    idea terminal修改为gitbash多彩
    企业微信如何发红包 企业微信向个人发红包 企业微信群无法发红包 企业微信无法发红包 企业微信无法发红包如何解决
    vue项目中使用ts(typescript)入门教程
    svg / d3-force 中如何给link的label文字加底色
    svg 如何使用滤镜给文字加底色
  • 原文地址:https://www.cnblogs.com/chy-2003/p/11673924.html
Copyright © 2011-2022 走看看