zoukankan      html  css  js  c++  java
  • 【BZOJ-4455】小星星 容斥 + 树形DP

    4455: [Zjoi2016]小星星

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 204  Solved: 137
    [Submit][Status][Discuss]

    Description

    小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品。她有n颗小星星,用m条彩色的细线串了起来,每条细线连着两颗小星星。有一天她发现,她的饰品被破坏了,很多细线都被拆掉了。这个饰品只剩下了n?1条细线,但通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树。小Y找到了这个饰品的设计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星。如果现在饰品中两颗小星星有细线相连,那么要求对应的小星星原来的图纸上也有细线相连。小Y想知道有多少种可能的对应方式。只有你告诉了她正确的答案,她才会把小饰品做为礼物送给你呢。

    Input

    第一行包含个2正整数n,m,表示原来的饰品中小星星的个数和细线的条数。
    接下来m行,每行包含2个正整数u,v,表示原来的饰品中小星星u和v通过细线连了起来。
    这里的小星星从1开始标号。保证u≠v,且每对小星星之间最多只有一条细线相连。
    接下来n-1行,每行包含个2正整数u,v,表示现在的饰品中小星星u和v通过细线连了起来。
    保证这些小星星通过细线可以串在一起。
    n<=17,m<=n*(n-1)/2

    Output

    输出共1行,包含一个整数表示可能的对应方式的数量。
    如果不存在可行的对应方式则输出0。

    Sample Input

    4 3
    1 2
    1 3
    1 4
    4 1
    4 2
    4 3

    Sample Output

    6

    HINT

    Source

    Solution

    一道容斥的好题

    我们一共要满足两个限制:1.树中的一个点对应图中一个点,且一一对应  2.树中两点有边的,图中两点也对应有边

    首先我们考虑最暴力的方法,如果同时满足两个限制,用$O(N^{N})$的时间去枚举,然后计数

    那如果我们放宽一个限制,只统计满足限制2的数目,这显然可以用树形DP在$O(N^{3})$的时间里得到的

    这里得到的是有$K$个点可以映射,但不保证$K$个点都被映射到,且不保证每个点只被映射一次

    那么考虑用容斥去统计出答案,答案就是$Ans(N)-Ans(N-1)+Ans(N-2)-Ans(N-3)+Ans(N-4).....$

    这样容斥的时候的枚举是$O(2^{N})$的

    所以总的复杂度是$O(2^{N}×N^{3})$的

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    #define LL long long
    #define MAXN 50
    int N,M;
    struct EdgeNode{int next,to;}edge[MAXN<<1];
    int head[MAXN],cnt=1;
    void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
    void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}
    LL dp[MAXN][MAXN],ans,now,tmp;
    int lt[MAXN][MAXN],bin[MAXN],tot,a[MAXN];
    void DFS(int now,int last)
    {
        for (int i=head[now]; i; i=edge[i].next)
            if (edge[i].to!=last) DFS(edge[i].to,now);
        for (int i=1; i<=tot; i++)
            {
                dp[now][i]=1;
                for (int j=head[now]; j; j=edge[j].next)
                    if (edge[j].to!=last)
                        {
                            tmp=0;
                            for (int k=1; k<=tot; k++)
                                if (lt[a[k]][a[i]]) tmp+=dp[edge[j].to][k];
                            dp[now][i]*=tmp;
                        }
            }
    }
    int main()
    {
        N=read(),M=read();
        for (int x,y,i=1; i<=M; i++) x=read(),y=read(),lt[x][y]=lt[y][x]=1;
        for (int x,y,i=1; i<=N-1; i++) x=read(),y=read(),InsertEdge(x,y);
        bin[0]=1; for (int i=1; i<=N; i++) bin[i]=bin[i-1]<<1;
        for (int i=1; i<=bin[N]-1; i++)
            {
                now=0; tot=0;
                for (int j=1; j<=N; j++) if (i&bin[j-1]) a[++tot]=j;
                DFS(1,0);
                for (int j=1; j<=tot; j++) now+=dp[1][j];
                if ((tot&1)==(N&1)) ans+=now; else ans-=now;            
            }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    微博(MicroBlog)
    面试题网站目录
    html 打印代码,支持翻页
    C#日期格式化
    职位英语简称注解
    专业术语:闭包、网站优化 Gzip 服务器端文件压缩
    1,由于代码已经过优化或者本机框架位于调用堆栈之上,无法计算表达式的值。
    JSON-JSON 百科
    api.js
    Android消息处理机制
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5793086.html
Copyright © 2011-2022 走看看