zoukankan      html  css  js  c++  java
  • bzoj 2560 串珠子

    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)为正整数且(nleq16),所有的(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
    ",f[m]);
    	return 0;
    }
    
  • 相关阅读:
    一起学windows phone7开发(二十四. Task 补遗)
    一起学windows phone7开发(二十.一 正式版中新增的 Panorama 和 Pivot Project)
    一起学WP7 XNA游戏开发(四. Input)
    一起学WP7 XNA游戏开发(五. Sound)
    一起学windows phone7开发(二十一.三 Map 控件深入学习)
    Daisy.wp7.Controls自定义的控件库
    一起学windows phone7开发(二十二.使用系统资源)
    一起学习Windows Phone7开发(二十三 Windows Phone7 Toolkit 补遗)
    一起学windows phone7开发(二十一.一 Silverlight bing map控件与 Pone7 map控件的比较)
    第一次试验报告
  • 原文地址:https://www.cnblogs.com/jklover/p/10000468.html
Copyright © 2011-2022 走看看