zoukankan      html  css  js  c++  java
  • 【BZOJ2560】串珠子(状压DP,容斥原理)

    题意:

    铭铭有n个十分漂亮的珠子和若干根颜色不同的绳子。现在铭铭想用绳子把所有的珠子连接成一个整体。
    现在已知所有珠子互不相同,用整数1到n编号。对于第i个珠子和第j个珠子,可以选择不用绳子连接,或者在c[i,j]根不同颜色的绳子中选择一根将它们连接。

    如果把珠子看作点,把绳子看作边,将所有珠子连成一个整体即为所有点构成一个连通图。特别地,珠子不能和自己连接。
    铭铭希望知道总共有多少种不同的方案将所有珠子连成一个整体。由于答案可能很大,因此只需输出答案对1000000007取模的结果。

    n<=16,a[i][j]<=1e9+7

    思路:

    还记得n个点有标号的无向连通图个数怎么求吗?如果记得的话,此题就简单了。
    用f[S]表示与1号点连通的点的状态为S的方案数。我们先与处理出g数组,g[S]=∏u,v∈S(c[u][v]+1),然后f[S]就等于g[S]减去S中某些点与1号点不连通的方案数。
    那么我们枚举此时与1号点连通的点的状态,其余的点与这个连通块均没有边相连,但是其余的点之间可以任意连边,
    所以有:
    f[S]=∑S′⊊Sf[S′]×g[S−S′]
    所以时间复杂度就是枚举子集的O(3^n)
    需要注意的是k=log(x)/log(2)+1这种写法似乎在BZOJ上不能用,需要预处理或者暴力
     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<cstring>
     6 #include<map>
     7 #include<set>
     8 #include<cmath>
     9 using namespace std;
    10 long long dp[1<<17],f[1<<17];
    11 long long a[17][17];
    12 const int MOD=1000000007;
    13 int n;
    14    
    15 int lowbit(int x)
    16 {
    17     return (x&(-x));
    18 }
    19  
    20 int who(int x)
    21 {
    22     int s=0;
    23     int k=x;
    24     while(k)
    25     {
    26         s++;
    27         k>>=1;
    28     }
    29     return s;
    30 }
    31  
    32 int main()
    33 {
    34    
    35     scanf("%d",&n);
    36     for(int i=1;i<=n;i++)
    37      for(int j=1;j<=n;j++) scanf("%lld",&a[i][j]);
    38     f[0]=1;
    39      
    40     int M=(1<<n)-1;
    41     for(int i=1;i<=M;i++)
    42     {
    43         int x=lowbit(i);
    44         int y=who(x);
    45         f[i]=f[i-x];
    46         for(int j=1;j<=n;j++)
    47          if((y!=j)&&(i&(1<<(j-1)))) f[i]=f[i]*(a[y][j]+1)%MOD;
    48     }
    49     
    50     dp[1]=1;
    51     for(int i=2;i<=M;i++)
    52      if(i&1)
    53      {
    54         int v=(i-1);
    55         dp[i]=f[i];
    56         while(v)
    57         {
    58             dp[i]=dp[i]-(f[v]*dp[i-v])%MOD;
    59             dp[i]=(dp[i]%MOD+MOD)%MOD; 
    60             v=((i-1)&(v-1)); 
    61         }
    62      }
    63     printf("%lld
    ",dp[M]);
    64     return 0;
    65 }
  • 相关阅读:
    Android开发经验小节2:循环利用你的小对象
    新技术你知道吗?Node.js的HelloWorld!
    css添加省略号(twxtoverflow:ellipsis)/图标精灵(background)
    htmlcss优先级(style,id,class,tag,*,继承,!important)
    html标签样式(块,内联,内联块,按内容,按显示分类)
    html浮动(float)
    css盒子模型
    htmlcss继承(inherit)
    htmldisplay(转化元素,block,inline,inlineblock,none)
    html定位position(固定,相对(relative),绝对(absolute))
  • 原文地址:https://www.cnblogs.com/myx12345/p/9302101.html
Copyright © 2011-2022 走看看