zoukankan      html  css  js  c++  java
  • [ZJOI2016]小星星

    题目描述

    小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品。她有n颗小星星,用m条彩色的细线串了起来,每条细线连着两颗小星星。

    有一天她发现,她的饰品被破坏了,很多细线都被拆掉了。这个饰品只剩下了n?1条细线,但通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树。小Y找到了这个饰品的设计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星。如果现在饰品中两颗小星星有细线相连,那么要求对应的小星星原来的图纸上也有细线相连。小Y想知道有多少种可能的对应方式。

    只有你告诉了她正确的答案,她才会把小饰品做为礼物送给你呢。

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

    输入样例#1:
    4 3
    1 2
    1 3
    1 4
    4 1
    4 2
    4 3
    输出样例#1:
    6

    说明

    题解:JudgeOnline/upload/201603/4455.txt

    本题题意大致是把树上的n个点赋为互不相同的1~n中的数字,同时满足连接关系,有多少方案

    如果要枚举的话,复杂度会O(n!)

    这种排列的问题可以转化,令状态k,是一个二进制数,为0则表示该数禁用

    对于每一个k,我们求出相应的不被禁用的数的可行排列(不需要满足互不相同)

    这时可以用容斥,总方案数=没有禁的方案-禁i的方案-禁j的方案+禁i,j的方案

    为什么?因为禁i时,因为不考虑重复,所以可能会有一部分是j未出现的方案,等于禁j的方案

    求方案数用树形dp

    f[i][j]表示i点编号j的方案

    f[i][j]=∏v(∑kf[v][k])  条件为图中j,k相连

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 struct Node
     7 {
     8     int next,to;
     9 }edge[2001];
    10 int w,q[101],n,m,map[51][51],head[101],num;
    11 long long f[21][21],ans;
    12 void add(int u,int v)
    13 {
    14     num++;
    15     edge[num].next=head[u];
    16     head[u]=num;
    17     edge[num].to=v;
    18 }
    19 void bit(int x)
    20 {int p;
    21     p=1;w=0;
    22     while (x)
    23     {
    24         if (x&1) q[++w]=p;
    25         p++;
    26         x>>=1;
    27     }
    28 }
    29 void dfs(int x,int fa)
    30 {int i,j,k;
    31     for (i=1;i<=w;i++)
    32     f[x][q[i]]=1;
    33         for (j=head[x];j;j=edge[j].next)
    34          if (edge[j].to!=fa)
    35          {
    36             dfs(edge[j].to,x);
    37               for (i=1;i<=w;i++)
    38               {long long s=0;
    39                 for (k=1;k<=w;k++)
    40                 if (map[q[i]][q[k]])
    41                 {    
    42                     s+=f[edge[j].to][q[k]];
    43                 }
    44                 f[x][q[i]]*=s;
    45               }
    46          }
    47 }
    48 int main()
    49 {int i,j,u,v;
    50 long long sum;
    51     cin>>n>>m;
    52      for (i=1;i<=m;i++)
    53      {
    54         scanf("%d%d",&u,&v);
    55         map[u][v]=map[v][u]=1;
    56      }
    57      for (i=1;i<=n-1;i++)
    58      {
    59         scanf("%d%d",&u,&v);
    60         add(u,v);add(v,u);
    61      }
    62        for (i=1;i<=(1<<n)-1;i++)
    63        {
    64             bit(i);
    65             //cout<<w<<endl;
    66             //memset(f,0,sizeof(f));
    67             sum=0;
    68              dfs(1,0);
    69              for (j=1;j<=w;j++)
    70               sum+=f[1][q[j]];
    71               //cout<<sum<<endl;
    72             if ((n&1)==(w&1)) ans+=sum;
    73             else ans-=sum;
    74        }
    75     cout<<ans;
    76 }
  • 相关阅读:
    项目
    关于我
    【转载】罗胖精选|什么样的自控方法才有效?
    知识管理——得到CEO脱不花女士的一次分享
    注意由双大括号匿名类引起的serialVersionUID编译告警
    持续集成、持续交付和持续部署
    Google Cayley图数据库使用方法
    任务的属性
    团队博客地址
    个人总结
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7379657.html
Copyright © 2011-2022 走看看