您的位置:首页 > 其它

ACM: uva 10253 - Series-Parallel…

2016-05-19 23:29 453 查看
Series-Parallel
Networks
 
In this problem you are expected to
count two-terminal series-parallel
networks
. These are electric networks considered topologically
or geometrically, that is, without the electrical properties of the
elements connected. One of the two terminals can be considered as
the source and the other
as the sink.

 

A two-terminal network will be considered series-parallel if it
can be obtained iteratively in the following way:

 

q       A
single edge is two-terminal series-parallel.

q       If G1 and G2 are
two-terminal series-parallel, so is the network obtained by
identifying the sources and sinks, respectively (parallel
composition).

q       If G1 and G2 are
two-terminal series-parallel, so is the network obtained by
identifying the sink
of G1 with
the source
of G2 (series
composition).

 

Note here that in a series-parallel network two nodes can be
connected by multiple edges. Moreover, networks are regarded as
equivalent, not only topologically, but also when interchange of
elements in series brings them into congruence; otherwise stated,
series interchange is an equivalence operation. For example, the
following three networks are equivalent:

 


 
 
Similarly, parallel interchange is also an equivalence
operation. For example, the following three networks are also
equivalent:

 



Now, given a number N, you are expected
to count the number of two-terminal series parallel networks
containing exactly Nedges. For example,
for N = 4,
there are
exactly 10 series-parallel
networks as shown below:

 



 
 

Input

Each line of the input file contains an
integer N (1 £ N £ 30) specifying
the number of edges in the network.
A line containing a zero
for N terminates the input
and this input need not be considered.

 

Output

For each N in the input
file print a line containing the number of two-terminal
series-parallel networks that can be obtained using
exactly N edges.

 

Sample Input

1
4
15
0
 

Sample Output

1
10
1399068
 

题意: 给定一个有n条边的串并联网络, 问有多少种可能.

 

解题思路:

      1.
每个串并联网络可以看成一棵树, 每次都可以将一个串并联分解成更加简单的串/并联网络. 并且

        
把它们看成一个节点. 假设一个并联节点为根, 第二层的所有非叶子节点都是串联节点, 第三层

        
的非叶子节点就是并联节点, 所有, 总是将复杂的网络拆分成相对简单的串/并联网络.

        
即: 设f(n)表示共n个叶子, 并且每个非叶子节点至少有两个子节点的树的数目.

      2.
题目给出, 子节点之间位置是无关的. 书上给出第一种解法是枚举n的所有整数划分, 问题变成

        
若干正整数之和的形式, 其中各个加数按从小到大排列.

         例如
5个叶子的子树, 划分情况有:

        
(1,1,1,1,1), (1,1,1,2), (1,1,3), (1,4), (1,2,2), (2,3), (5);

        
最后, 每棵子树之间是相互独立, 并且相同叶子节点数量的看成同一种元素, 问题变成可重复选择

        
的组合问题: C(n+k-1, k);

      3.
书上给出的第二种高效解法. 设dp[i][j]表示每棵子树最多包含i个叶子, 一共有j个叶子的方案数.

         有f(n)
= dp[n-1]
;

        
状态方程: dp[i][j] = sum( C(f(i)+p-1, p)*dp[i-1][j-p*i] |
p>=0, p*i<=j );

 

代码解法一:

#include <cstdio>

#include <iostream>

#include <cstring>

using namespace std;

#define MAX 33

typedef long long ll;

int n;

ll dp[MAX];

int g[MAX];

inline int min(int a, int b)

{

 return a < b ? a : b;

}

ll C(ll n, ll m)

{

 double ans = 1;

 for(int i = 0; i < m; ++i)

  ans *= n-i;

 for(int j = 1; j <= m; ++j)

  ans /= j;

 return (ll) (ans+0.5);

}

void DP(int s, int res, int cur)

{

 if(res == 0)

 {

  ll temp = 1;

  for(int i = 1; i
<= cur-1; ++i)

   temp *=
C(dp[i]+g[i]-1, g[i]);

  dp[cur] += temp;

  return ;

 }

 int size = min(res, cur-1);

 for(int i = s; i <= size;
++i)

 {

  g[i]++;

  DP(i, res-i, cur);

  g[i]--;

 }

}

void init()

{

 memset(g, 0, sizeof(g));

 memset(dp, 0, sizeof(dp));

 dp[1] = 1;

 for(int i = 2; i <= 30; ++i)

  DP(1, i, i);

}

int main()

{

 freopen("input.txt", "r", stdin);

 init();

 while(scanf("%d", &n) !=
EOF)

 {

  if(n == 0) break;

  printf("%lld\n", n == 1 ? 1 :
2*dp
);

 }

 return 0;

}

 

解法二:

#include <cstdio>

#include <iostream>

#include <cstring>

using namespace std;

#define MAX 33

typedef long long ll;

int n;

ll dp[MAX][MAX], f[MAX];

ll C(ll n, ll m)

{

 double ans = 1;

 for(int i = 0; i < m; ++i)

  ans *= (n-i);

 for(int j = 0; j < m; ++j)

  ans /= (j+1);

 return (ll) (ans+0.5);

}

void init()

{

 int i, j;

 memset(dp, 0, sizeof(dp));

 memset(f, 0, sizeof(f));

 f[1] = 1;

 for(i = 0; i <= 30; ++i) dp[i][0]
= 1;

 for(i = 1; i <= 30; ++i)

 {

  dp[i][1] = 1;

  dp[0][i] = 0;

 }

 for(i = 1; i <= 30; ++i)

 {

  for(j = 2; j <=
30; ++j)

  {

   dp[i][j] =
0;

   for(int p =
0; j-p*i >= 0; ++p)

   {

    dp[i][j]
+= C(f[i]+p-1, p)*dp[i-1][j-p*i];

   }

  }

  f[i+1] = dp[i][i+1];

 }

}

int main()

{

// freopen("input.txt", "r", stdin);

 init();

 while(scanf("%d", &n) !=
EOF)

 {

  if(n == 0) break;

  printf("%lld\n", n == 1 ? 1 :
2*f
);

 }

 return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: