• bzoj2560 串珠子


    Description

      铭铭有n个十分漂亮的珠子和若干根颜色不同的绳子。现在铭铭想用绳子把所有的珠子连接成一个整体。
      现在已知所有珠子互不相同,用整数1到n编号。对于第i个珠子和第j个珠子,可以选择不用绳子连接,或者在ci,j根不同颜色的绳子中选择一根将它们连接。如果把珠子看作点,把绳子看作边,将所有珠子连成一个整体即为所有点构成一个连通图。特别地,珠子不能和自己连接。
      铭铭希望知道总共有多少种不同的方案将所有珠子连成一个整体。由于答案可能很大,因此只需输出答案对1000000007取模的结果。 

    Input

     标准输入。输入第一行包含一个正整数n,表示珠子的个数。接下来n行,每行包含n个非负整数,用空格隔开。这n行中,第i行第j个数为ci,j。 

    Output

     标准输出。输出一行一个整数,为连接方案数对1000000007取模的结果。

    Sample Input

    3
    0 2 3
    2 0 4
    3 4 0

    Sample Output

    50

    HINT

      对于100%的数据,n为正整数,所有的ci,j为非负整数且不超过1000000007。保证ci,j=cj,i。每组数据的n值如下表所示。
      编号 1 2 3 4 5 6 7 8 9 10    
      n 8 9 9 10 11 12 13 14 15 16  

    正解:状压dp。

    这道题很玄学,感觉还是懵懵懂懂。。今天的出题人太丧病了。。

    考虑状压dp,我们把n个点压成二进制数。

    我们设两个数组,g[s]表示s状态下的所有情况,即s状态下的点两两之间任意连边(包括不连边的情况),f[s]表示s状态下的合法情况,即使得s状态下所有点连通的合法情况。那么答案就是f[2^n-1]。

    然后我们可以很容易地求出g[s],我们求出g[s]后,考虑如何求f[s],f[s]就是g[s]减去所有的不合法情况。那么我们可以枚举s的所有子集,设子集为i,那么不合法的情况就是g[i]*f[s^i],我们减去这些情况,就能求出f[s]了。

    枚举子集很玄学。。我反正不知道这是怎么回事,看了网上大神的博客。。

    http://www.cnblogs.com/jffifa/archive/2012/01/16/2323999.html

    for (int x = S; x; x = (x-1)&S)

    大概是这个鬼东西。。大神的证明:

    x = (x-1)&S实际上是把S中的0全部忽略,并不断减1的结果,比如S=1011,则x分别为:1011, 1010, 1001, 1000, 0011, 0010, 0001。忽略S中第二位的0其实就是111, 110, 101, 100, 011, 010, 001。

    称S中的1所在位为有效位,0所在位为无效位,则x中的无效位必为0,有效位为0或1,比如S=1011,x=1001(有效位加下划线)。-1就是加上-1补码1111…,可以想成把无效位的1先加上去,比如x=1001变成1101,再加有效位的1。由于无效位加完肯定是1,会把有效位的进位“传递”下去,然后再位与S使得无效位变成0,实际就相当于有效位加上1111…,也就是有效位-1。

    于是我们就能解决这题了。其实我还没搞懂为什么要这么搞。

     1 //It is made by wfj_2048~
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <cstring>
     5 #include <cstdlib>
     6 #include <cstdio>
     7 #include <vector>
     8 #include <cmath>
     9 #include <queue>
    10 #include <stack>
    11 #include <map>
    12 #include <set>
    13 #define inf (1<<30)
    14 #define il inline
    15 #define RG register
    16 #define ll long long
    17 #define rhl 1000000007
    18 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    19 
    20 using namespace std;
    21 
    22 ll f[1<<16],g[1<<16],bin[20],a[20][20],n;
    23 
    24 il int gi(){
    25     RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    26     if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x;
    27 }
    28 
    29 il void work(){
    30     n=gi(),bin[0]=1;
    31     for (RG int i=1;i<=n;++i)
    32     for (RG int j=1;j<=n;++j) a[i][j]=gi();
    33     for (RG int i=1;i<=n;++i) bin[i]=bin[i-1]<<1;
    34     for (RG int k=0;k<bin[n];++k){
    35     f[k]=1;
    36     for (RG int i=1;i<n;++i) if (k&bin[i-1])
    37         for (RG int j=i+1;j<=n;++j) if (k&bin[j-1]) f[k]=f[k]*(a[i][j]+1)%rhl;
    38     g[k]=f[k]; RG int i=k^(k&-k); //枚举真子集?!
    39     for (RG int j=i;j;j=(j-1)&i) f[k]=(f[k]-g[j]*f[k^j]%rhl+rhl)%rhl;
    40     }
    41     printf("%lld
    ",f[bin[n]-1]); return;
    42 }
    43 
    44 int main(){
    45     File("bunch");
    46     work();
    47     return 0;
    48 }
  • 相关阅读:
    虚拟机操作系统文件夹空间不足解决办法——对虚拟硬盘进行分区和格式化及 挂载到某个文件夹下
    设计模式(二十一)—职责链模式(行为型)
    VMware 中添加新的虚拟磁盘的方法
    设计模式(二十二)—中介者模式(行为型)
    level of detail algorithmrendering of massive realtime terrain
    金融领域实施项目特点总结
    第35周星期日总结
    第36周星期一小结
    第32周星期二总结
    第35周星期三小结
  • 原文地址:https://www.cnblogs.com/wfj2048/p/6501856.html
Copyright © 2020-2023  润新知