/**//* 给出一个无向图n<=10,运行删掉一些边,求使得最后是一棵树而且只剩k个叶子的方法数 知道是状态dp,表示不出来 看了别人的,原来需要两个mask dp[tree,leaf],tree,leaf均是mask,表示当前整棵树的节点,以及叶子节点 --------------------OMG 转移是枚举边,扩大tree,leaf,即增加一个叶子(但也有可能把原来是叶子的变为非叶子)
注意每个状态(tree,leaf)最后要除以叶子leaf的数目,因为扩展这些叶子leaf都得到同样的一棵树tree,即这个tree 被算了leaf次. 另外注意的是只有两个节点时,它们都是leaf 初始化为dp[1<<i][1<<i] = 1 即只有一个叶子 */ #include<iostream> #include<cstring> #include<map> #include<algorithm> #include<stack> #include<queue> #include<cmath> #include<string> #include<cstdlib> #include<vector> #include<cstdio> #include<set> #include<list> #include<numeric> #include<cassert> #include<ctime> #include<bitset>
using namespace std;
int dp[1<<10][1<<10]; int bitCount[1<<10];
int main() { #ifndef ONLINE_JUDGE freopen("in","r",stdin); #endif
for (int mask = 1; mask < (1<<10); mask++) { bitCount[mask] = bitCount[mask>>1] + (mask&1); }
for (int n, m, k; ~scanf("%d%d%d", &n, &m, &k); ) { vector<pair<int,int> > edge; int u, v; for (int i = 0; i < m ; i ++) { scanf("%d%d", &u, &v); u--; v--; edge.push_back(make_pair(u,v)); edge.push_back(make_pair(v,u)); } int limit = 1<<n; fill(dp[0], dp[limit] , 0); for (int i = 0; i < n; i++) { dp[1<<i][1<<i] = 1;//leaf } for (int tree = 1; tree < limit ; tree++) { for (int leaf = 1; leaf < limit ; leaf ++) { if(dp[tree][leaf] != 0) { dp[tree][leaf] /= bitCount[leaf]; for ( vector<pair<int,int> >::iterator it = edge.begin(); it != edge.end(); it++) { u = it->first; v = it->second; if((tree & (1<<v)) || !(tree&(1<<u))){ continue; } int _tree = tree | (1<<v); int _leaf = leaf | (1<<v); if((_leaf & (1<<u)) && bitCount[_tree] != 2) { _leaf ^= (1<<u); } dp[_tree][_leaf] += dp[tree][leaf]; } } } } int ans = 0; for (int leaf = 1; leaf < limit ; leaf ++) { if(bitCount[leaf] == k) { ans += dp[limit-1][leaf]; } } printf("%d\n", ans); } return 0; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|