zoukankan      html  css  js  c++  java
  • 【HDOJ5713】K个联通块(状压DP,计数)

    题意:有一张无重边的无向图, 求有多少个边集,使得删掉边集里的边后,图里恰好有K个连通块。 

    1T20
    1KN14
    0MN(N+1)/2
    1a,bN

    思路:From http://blog.csdn.net/di4covery/article/details/51699544

    一个简单的结论:删除边集的个数 = 选择边集的个数 , 这样我们就可以把问题转化为选取若干条边使得图里面恰好有K个联通块。

    问题可以转化成三个状态压缩DP来完成(这三个DP都不难)

    1、num[ mask ] 表示选取mask状态的点两两连边的边数。(这是一个很小的数)

    这个数组我们通过状态压缩DP来求

    令 u = lowbit (mask)  (即mask状态中编号最小的那个点)

    枚举mask中的点v,计算边u,v的个数tmp

    num [ mask ] = num [ mask ^u ] + tmp;

    2、f [ mask ] 表示选取mask状态的点 ,构成一个联通块 的方案数

    同样,利用上一次求出来的num数组,状态压缩DP来求

    容斥原理 : 合法方案数 = 总方案数 - 不合法方案数

    总方案数 :  2 ^ num( mask ) (每条边选或者不选)

    不合法方案数 = tmp: 

    令 u = lowbit (mask) 

    枚举mask一个不包含u的子集s,tmp = tmp + f(mask ^ s) * ( 2 ^ num[ s ] );

    上面的式子可以理解为枚举一个包含u的联通块,然后剩下的点两两之间的边选或者不选,这些边不会连接之前的联通块

    f [ mask ] = 2 ^ num( mask) - tmp;

    3、F[ mask ] [ n ]表示选取mask状态的点,构成n个联通块的方案数

    实际上 f[ mask ]是 F[mask][1] ,剩下的状态压缩DP相对简单

    枚举mask,枚举n

    令u = lowbit( mask ),枚举mask一个不包含u的子集s

    F[ mask ][ n ] = F[ s ][ n-1 ] * F[ mask ^ s ][ 1 ]

    上面的式子等价于F[ mask ][ n ] = F [ s ][ n-1 ] * f[ mask ^ s ]

    答案即为F[ mask ] [ n ] (mask为所有点都选择的状态,就是2^n - 1)

    Pascal对拍已A,卡常没办法,估计如果去年现场做要跪(现在也跪)

     1 const mo=1000000009;
     2 var g:array[0..35000,0..15]of int64;
     3     f:array[0..35000]of int64;
     4     two:array[0..200]of int64;
     5     num:array[0..35000]of longint;
     6     a:array[0..20,0..20]of longint;
     7     cas,v,i,t,x,y,sta,max,k1,n,m,j:longint;
     8     tmp:int64;
     9 
    10 function lowbit(x:longint):longint;
    11 begin
    12  exit(x and (-x));
    13 end;
    14 
    15 begin
    16  assign(input,'hdoj5713.in'); reset(input);
    17  assign(output,'hdoj5713.out'); rewrite(output);
    18  readln(cas);
    19  two[0]:=1;
    20  for i:=1 to 200 do two[i]:=two[i-1]*2 mod mo;
    21  for v:=1 to cas do
    22  begin
    23   readln(n,m,k1);
    24 
    25 
    26   max:=(1<<n)-1;
    27   for i:=1 to n do
    28    for j:=1 to n do a[i,j]:=0;
    29   for i:=1 to max do
    30   begin
    31    num[i]:=0; f[i]:=0;
    32   end;
    33   for i:=1 to max do
    34    for j:=1 to n do g[i,j]:=0;
    35   for i:=1 to m do
    36   begin
    37    read(x,y);
    38    a[x,y]:=1; a[y,x]:=1;
    39   end;
    40   for i:=1 to max do
    41   begin
    42    x:=lowbit(i); y:=round(ln(x)/ln(2))+1;
    43    num[i]:=num[i xor x];
    44    for j:=1 to n do
    45     if i and (1<<(j-1))>0 then num[i]:=(num[i]+a[y,j]) mod mo;
    46   end;
    47   for sta:=1 to max do
    48   begin
    49    x:=lowbit(sta);
    50    t:=sta xor x; y:=t; tmp:=0;
    51    while t>0 do
    52    begin
    53     tmp:=tmp+f[sta xor t]*two[num[t]];
    54     tmp:=tmp mod mo;
    55     t:=y and (t-1);
    56    end;
    57    f[sta]:=(two[num[sta]]-tmp) mod mo;
    58   end;
    59   for i:=1 to max do g[i,1]:=f[i];
    60   for sta:=1 to max do
    61    for i:=2 to k1 do
    62    begin
    63     x:=lowbit(sta);
    64     t:=sta xor x; y:=t;
    65     while t>0 do
    66     begin
    67      g[sta,i]:=g[sta,i]+g[t,i-1]*f[sta xor t];
    68      g[sta,i]:=g[sta,i] mod mo;
    69      t:=y and (t-1);
    70     end;
    71 
    72 
    73    end;
    74 
    75 
    76   writeln('Case #',v,':');
    77   writeln(g[max,k1]);
    78  end;
    79 
    80  close(input);
    81  close(output);
    82 end.

    对拍用的C++ 1000+MS

     1 #include <iostream>  
     2 #include <cstdio>  
     3 #include <cstring>  
     4 #define MAXMASK 65537  
     5 #define N 20  
     6 #define mod 1000000009LL  
     7   
     8 using namespace std;  
     9   
    10 int e[N][N],n,m,k,MASK,num[MAXMASK];  
    11 long long F[MAXMASK][N],f[MAXMASK];  
    12   
    13 inline int lowbit(int x){return x & (-x);};  
    14   
    15 int edge(int s, int p) {  
    16     int ans = 0;  
    17     for (int i = 1; i <= n; i++)   
    18         if ((1<<(i-1)) == p) {p = i;break;}  
    19     for (int i = 1; i <= n; i++) if ((1<<(i-1))&s) ans += e[i][p];  
    20     return ans;  
    21 }  
    22   
    23 int main()  
    24 {  
    25    freopen("hdoj5713.in","r",stdin);
    26    freopen("right.out","w",stdout);
    27     int T = 0;  
    28     scanf("%d",&T);  
    29     for (int rank=1;rank<=T;rank++)  
    30     {  
    31         memset(e,0,sizeof(e));  
    32         memset(F,0,sizeof(F));  
    33         memset(f,0,sizeof(f));  
    34         memset(num,0,sizeof(num));  
    35         scanf("%d%d%d",&n,&m,&k);  
    36         MASK = (1 << n) - 1;  
    37         for (int i=1;i<=m;i++) {  
    38             int a,b;  
    39             scanf("%d%d",&a,&b);  
    40             e[a][b] = e[b][a] = 1;//顺带处理自环:)   
    41         }  
    42         //计算mask状态下的边数   
    43         for (int i=1;i<=MASK;i++) {  
    44             int t = lowbit(i);  
    45             num[i] = num[i^t] + edge(i,t);//往状态里新增加一个点   
    46         }  
    47           
    48         //状态压缩DP求小f   
    49           
    50         for (int s=1;s<=MASK;s++){  
    51             int t = lowbit(s);  
    52             long long tmp = 0LL;  
    53             for (int i=(s^t);i>0;i=((i-1)&(s^t))) {  
    54                 tmp += f[s^i] * 1LL*(1LL << num[i]);  
    55                 tmp %= mod;  
    56             }  
    57             f[s] = (1LL*(1LL<<num[s]) - tmp) % mod;  
    58         }  
    59        // for (int s=1;s<=MASK;s++) printf("%d
    ",f[s]);
    60         //小f为大F的第一项   
    61         for (int s=1;s<=MASK;s++) F[s][1] = f[s];  
    62           
    63         //状态压缩DP求大F   
    64         for (int s=1;s<=MASK;s++)  
    65             for (int i=2;i<=k;i++) {  
    66                 int t = lowbit(s);  
    67                 for (int j=s^t;j>0;j=(j-1)&(s^t))  {//枚举s的子集  
    68                     F[s][i] += F[j][i-1] * f[s^j];  
    69                     F[s][i] %= mod;  
    70                 }  
    71             }  
    72           
    73         //防止答案小于0   
    74         while (F[MASK][k] < 0) F[MASK][k] += mod;  
    75         printf("Case #%d:
    %I64d
    ", rank, F[MASK][k]);  
    76     }  
    77     return 0;  
    78 }  
  • 相关阅读:
    数据结构(三)栈与递归
    机器学习(二)------ 回归
    数据结构(二)线性表
    数据结构(一)数据结构基础
    机器学习 (一)------分类
    操作系统概述
    NumPy函数库基础
    总线与输入输出子系统
    FT VIEW SE高效开发之全局对象
    STUDIO 5000 V32新CRACK和新功能
  • 原文地址:https://www.cnblogs.com/myx12345/p/7367549.html
Copyright © 2011-2022 走看看