- 又是这种类型的DP,看似需要 n! 的复杂度,其实定义好dp状态就行啦!
题意:
给定一个包含 N 个点的无向图,给定
k 条边,表示无向图中这些边不存在,其余不包括在这 k 条边中的边都存在,求走完整个图(每个点只能访问一次)有多少种走法?
范围:
1≤N≤105,0≤k≤7
思路:
转化一下,问题就是求有多少种 1 到
n 排列使得排列中不会出现那 k 对数在排列中相邻。因为
k 比较小,而且这些特殊点最多也只有 14 个,所以我们可以去数位 dp 枚举这14个点的排列状态,然后去加入剩余没有用过的特殊点,如果相邻的两个特殊点属于上面 k 对中的一对的话,那么就这两个点之间必须至少加入一个点,考虑dp 状态 dp[i][j][k] 表示 i 状态下,最后一个被排列的点为j ,用掉了 k <script type="math/tex" id="MathJax-Element-17">k</script> 个非特殊点的排列方式!转移就很简单了啊!略。。。。
代码:
let k = faulty_nodes.size()
let ans = 0 //counter variable
let normal_nodes = N - k;
for mask = 1 to (2^k-1)
{
for first_node = 0 to k-1
{
for number_tied = 0 to k-1
{
//appending a new node to the beginning of the arrangement that
//is given by mask.
for new_first = 0 to k-1
{
if(new_first bit in mask == 0)
{
new_mask = bitwise_or(mask, 2^new_first)
missing_edge = 1 if edge (new_first, first_node) missing else 0
//adding to the count of sequences starting with new_first and
//containing faulty nodes as the ones in the new_mask
dp[new_mask][new_first][number_tied + missing_edge] += dp[mask][first_node][number_tied];
//note that if the edge (new_first, first_node) is missing,
//we will have to tie an element to first_node, i.e.,
//increasing number_tied by 1.
}
}
if(mask == (2^k - 1))
{
//if all the faulty nodes have been arranged then we can
//count the number of valid permutations for this
//particular arrangement
total_objects = N - number_tied;
val = dp[mask][first_node][number_tied];
//getting all ways of arranging items
get_ways = (total_objects choose k) * (val);
//multiplying the number of ways of permuting normal nodes.
get_ways = (get_ways * factorial[normal_nodes]);
//adding to the counter variable
ans = (ans + get_ways);
}
}
}
}