码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 2560 串珠子

时间:2018-11-22 14:35:41      阅读:153      评论:0      收藏:0      [点我收藏+]

标签:漂亮   \n   include   选择   written   const   子集   span   space   

Written with StackEdit.

Description

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

Input

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

Output

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

Sample Input

3
0 2 3
2 0 4
3 4 0

Sample Output

50

HINT

对于\(100\%\)的数据,\(n\)为正整数且\(n\leq16\),所有的\(c_{i,j}\)为非负整数且不超过\(1000000007\)。保证\(c_{i,j}=c_{j,i}\)

Solution

  • \(n\)较小,考虑状压\(dp\).
  • \(f[S]\)表示集合\(S\)中的点联通时的方案数,\(g[S]\)表示集合\(S\)中的数任意连边时的方案数.那么算出\(S\)中的点不连通的方案数和\(g[S]\)即可求出\(f[S]\).
  • 有状态转移方程\(f[S]=g[S]?∑_{S^{‘}∈S}f[S^{‘}]?g[S\)^\(S^{‘}]\).
  • 为了避免重复计数,需要固定一个点作为代表元素,即\(S^{‘}\)中必须包含它.
#include<bits/stdc++.h>
using namespace std;
typedef long long LoveLive;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>‘9‘||jp<‘0‘)&&jp!=‘-‘)
        jp=getchar();
    if (jp==‘-‘)
        {
            fh=-1;
            jp=getchar();
        }
    while (jp>=‘0‘&&jp<=‘9‘)
        {
            out=out*10+jp-‘0‘;
            jp=getchar();
        }
    return out*fh;
}
const int P=1e9+7;
inline int add(int a,int b)
{
    return (a + b) % P;
}
inline int mul(int a,int b)
{
    return 1LL * a * b % P;
}
int fpow(int a,int b)
{
    int res=1;
    while(b)
        {
            if(b&1)
                res=mul(res,a);
            a=mul(a,a);
            b>>=1;
        }
    return res;
}
int inv(int x)
{
    return fpow(x,P-2);
}
const int MAXN=20;
const int MAXS=(1<<20)+10;
int c[MAXN][MAXN];
int n,m;
int f[MAXS],g[MAXS];
//f是必须连通的方案数,g是随便连边的方案数 
int main()
{
    n=read();
    m=(1<<n)-1;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
            c[i][j]=read();
    for(int i=0;i<=m;++i)   
        {
            g[i]=1;//初始化,未连边 
            for(int j=1;j<=n;++j)//选择j作为这个子集的代表元素 
                {
                    if(i&(1<<(j-1)))//j在这个子集图中 
                        {
                            for(int k=j+1;k<=n;++k)
                                {
                                    if(i&(1<<(k-1)))
                                        g[i]=mul(g[i],c[j][k]+1);
                                }   
                        } 
                }
        }
    for(int i=1;i<=m;++i)
        {
            for(int S=i&(i-1);S;S=i&(S-1))
                {
                    if(!((i^S)&(i&(-i))))
                        f[i]=add(f[i],mul(f[S],g[i^S]));
                }
            f[i]=add(g[i],P-f[i]);
        }
    printf("%d\n",f[m]);
    return 0;
}

bzoj 2560 串珠子

标签:漂亮   \n   include   选择   written   const   子集   span   space   

原文地址:https://www.cnblogs.com/jklover/p/10000468.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!