 /**//*
給出一個(gè)無(wú)向圖n<=10,運(yùn)行刪掉一些邊,求使得最后是一棵樹(shù)而且只剩k個(gè)葉子的方法數(shù)
知道是狀態(tài)dp,表示不出來(lái)
看了別人的,原來(lái)需要兩個(gè)mask
dp[tree,leaf],tree,leaf均是mask,表示當(dāng)前整棵樹(shù)的節(jié)點(diǎn),以及葉子節(jié)點(diǎn) --------------------OMG
轉(zhuǎn)移是枚舉邊,擴(kuò)大tree,leaf,即增加一個(gè)葉子(但也有可能把原來(lái)是葉子的變?yōu)榉侨~子)

注意每個(gè)狀態(tài)(tree,leaf)最后要除以葉子leaf的數(shù)目,因?yàn)閿U(kuò)展這些葉子leaf都得到同樣的一棵樹(shù)tree,即這個(gè)tree
被算了leaf次 .
另外注意的是只有兩個(gè)節(jié)點(diǎn)時(shí),它們都是leaf
初始化為dp[1<<i][1<<i] = 1 即只有一個(gè)葉子
*/
#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
搜索
最新評(píng)論

|
|