这道题目是hihoCoder Challenge 27的C题,我考虑了5天:(。

计数问题。由于树的结构的特殊性(树具有递归结构),不难想到思路是树形DP。由于这是【计数问题】而非【优化问题】,我们思考时应该着重考虑两个基本的计数原理:加法原理与乘法原理,而非所谓【最优子结构】。

DP 状态

关于DP状态设计,我的思考过程如下:

指定一节点作为根,转化成有根树。我们考虑子问题:

子树 $v$ 中的路线方案数。

然后考虑

将子树 $v$ 中的所有可能的方案压缩到一个怎样的子空间中能实现从(子树) $v$ 到其父节点 (子树)$u$ 的状态转移?

DP状态要有助于计算通过 $u$ 的路线的方案数。而这样的路线由任意两不同的自由节点(非路线端点) $v_1$、$v_2 \text{ s.t. } \text{LCA}(v_1,v_2) = u$ 所确定。

状态1

$dp[i][j]$:子树 $i$ 中有 $j$ 个自由点的方案数。

然而这 $j$ 个自由点到点 $i$ 的路径在【任意一条边最多被 $k$ 条路线经过】的限制下可能互斥。

状态2

在 $dp[i][j]$: 从子树 $i$ 中选择 $j$ 条【独立路径】伸出来的方案数。

这个状态是可以转移的。这里需要指出的一点是,我们不采用类似于 “子树 $i$ 中有 $j$ 条独立路径伸出来” 这样的表述来定义状态,而采用 “选择” 这个词。

转移方程

同大多数树形 DP 一样,状态转移是一个合并子树的过程。在计算子树 $u$ 中的方案数的过程中,对于 $u$ 的儿子 $v$,将子树 $v$ 的状态合并到子树 $u$ 中的方法:

枚举从子树 $v$ 中选出的【用于和前面的独立路径配对的独立路径】的数目 $x$ 和【不配对的独立路径】的数目 $y$

Implementation

#include <bits/stdc++.h>
using namespace std; using ll = long long; const int mod = 1e9+7; const int N = 305; vector<int> g[N];
int size[N]; int dp[N][N]; void add_mod(int &x, int y)
{
x += y;
if(x >= mod)
x -= mod;
} int f[N]{1};
int c[N][N]; void prep(int n)
{
for(int i=1; i<=n; ++i)
f[i]=ll(f[i-1])*i%mod; for(int i=0; i<=n; i++)
c[i][0] = 1;
for(int i=1; i<=n; i++)
for(int j=1; j<=i; j++)
add_mod(c[i][j], c[i-1][j-1]), add_mod(c[i][j], c[i-1][j]);
} int cur[N]; int n, k; void dfs(int u, int fa)
{
size[u] = 1;
dp[u][0] = 1;
dp[u][1] = 1; for(auto &v: g[u])
{
if(v != fa)
{
dfs(v, u);
for(int x=0; x <= min(size[v], k); ++x) // pair
{
for(int y=0; x+y <= min(size[v], k); ++y) // single
{
int tmp = ll(dp[v][x+y]) * c[x+y][y] % mod; if(tmp == 0)
continue; for(int i=x; i<=size[u]; ++i)
{
add_mod(cur[i-x+y], ll(tmp) * dp[u][i] % mod * c[i][x] % mod * f[x] % mod); // error-prone
}
}
} size[u] += size[v]; for(int i=0; i<=size[u]; ++i)
{
dp[u][i] = cur[i];
cur[i] = 0;
}
}
}
} int main()
{
scanf("%d%d", &n, &k);
prep(n);
for(int i=1; i<n; i++)
{
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
} dfs(1, 1); printf("%d\n", dp[1][0]);
return 0;
}

要格外注意递归函数中的全局变量。

总结

前两天在知乎上看到一个解释【DP状态的无后效性】的回答,思考这个问题的过程中感到很受用。

一般我们说的最优解问题,最朴素的做法是搜索所有的方案,大部分时候这个复杂度是不能接受的。对某些问题来说,我们可以将问题分解成子问题,子问题具有最优子结构的特点:对子问题的优化可以带来对整个问题的优化。但仅仅是这样并没有很大的帮助,因为我们对子问题的优化可能会导致整个问题的其他部分的解法变得不成立,或者变得不够优化,这样我们仍然不能有效计算整个问题的最优解。但是,某些情况下,子问题对于整个问题的影响,可以归纳到一个比“所有子问题解法”的空间小得多的“子问题状态”空间中,只要子问题解决后的状态处于某个状态,它对于整个问题的影响就是一致的,这样如果已知子问题处于某个状态,我们就可以求出这个状态条件下子问题的最优解,当全局最优且这个子问题取这个状态时,子问题本身的解法一定是我们刚刚求出的最优解。这样我们只需要对每个子问题的每个状态计算最优解,然后通过这些最优解的递推关系就可以求出整个问题的最优解。这种子问题对主问题的影响可以总结为少数“状态”的特性就叫做无后效性,意味着只要状态一致,具体经过怎样的步骤到达这一状态是没有影响的。

SOURCE

hihoCoder #1471 拥堵的城市的更多相关文章

  1. 天气预报API(二):全球城市、景点代码列表(“旧编码”)

    说明 2016-12-10 补充 (后来)偶然发现中国天气网已经有城市ID列表的网页...还发现城市编码有两种,暂且称中国天气网这些编码为旧标准"旧编码"的特征是 9个字符长度; ...

  2. 【hihoCoder】1041. 国庆出游

    问题:详见http://hihocoder.com/problemset/problem/1041 有n个城市,城市编号为1-n,城市间有n-1条路(所以,城市路网是一棵树).给定一个序列S,要求判断 ...

  3. 基于tp框架实现的递归城市查询

    控制器层: 接下来就是模型层: 如果说你的数据量庞大到致使apache或者nginx停止运行,有两点原因: 1.代码耦合性不高,代码有错误: 2.php.ini里面有一个memory_limit的这个 ...

  4. JQUERY省、市、县城市联动选择

    JQUERY 插件开发——CITYLINKAGE(省.市.县城市联动选择) 第一部分:背景   开发源于需求,本次城市联动选择插件算是我写插件的一个特例吧,不是我目前工作需要些的,算是兴趣驱使吧.之前 ...

  5. VR全景智慧城市常诚:信息技术点亮“智慧城市”

    亚太城市峰会暨市长论坛日前在澳大利亚昆士兰州首府布里斯班举行,"智慧城市"成为焦点议题.来自135个国家和地区的市长.副市长及代表们共同讨论如何利用高新科技解决城市发展中的问题,让 ...

  6. 全国地区的省份、城市、区县 最新Sql脚本

    IF (EXISTS(SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TB_Province]') AND type =' ...

  7. 最新!2016中国城市GDP排名出炉

    2017年1月20日,国家统计局公布:2016年中国国内生产总值GDP达744127亿元,同比增长6.7%,城市GDP方面:截至1月20日,全国大部分城市的去年经济运行数据已经公布,根据信息汇总,20 ...

  8. Jquery 插件开发——citylinkage(省、市、县城市联动选择)

    第一部分:背景  开发源于需求,本次城市联动选择插件算是我写插件的一个特例吧,不是我目前工作需要些的,算是兴趣驱使吧.之前呢,一直想写这个插件,然后错过了一个写这个插件的机会(这个得回顾到很久以前了. ...

  9. AI-Info-Micron-Insight:V2X 自主性:帮助减少事故、排放和交通拥堵

    ylbtech-AI-Info-Micron-Insight:V2X 自主性:帮助减少事故.排放和交通拥堵 1.返回顶部 1. V2X 自主性:帮助减少事故.排放和交通拥堵 一辆汽车冲到你的车道上.晚 ...

随机推荐

  1. [翻译] API测试的最佳实践 - 介绍

    API测试的最佳实践 - 介绍 在上一篇“是什么让API测试很叼”一文中,我们讨论API与其他形式的软件测试的差异.部分是因为API之间的通信压根就没考虑让你能读懂,纯粹是为了方便计算机之间的交互而设 ...

  2. mysqldumpslow及explain使用简介

  3. bat 批处理测试局域网速度 两端电脑

    C:\Users\Administrator>iperf3 iperf3: parameter error - must either be a client (-c) or server (- ...

  4. POJ 2449 Remmarguts' Date

    Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 30725   Accepted: 8389 Description &quo ...

  5. codevs 1313 质因数分解

    时间限制: 1 s  空间限制: 128000 KB  题目等级 : 青铜 Bronze 题目描述 Description 已知正整数 n是两个不同的质数的乘积,试求出较大的那个质数 . 输入描述 I ...

  6. (九)maven之聚合多模块

    聚合项目 一些开源项目,都会把自己的源代码公开到github之类的网站上,我们通过下载其代码,在本地执行maven install,可以把代码编译成jar包安装到本地仓库.而一个项目通常有多个模块,比 ...

  7. sublime text 3中emmet常用技巧

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. Java-NestedClass(Interface).

    内部类(Nested Class) 内部类:即在一个类中还包含着另外一个类,一般是作为匿名类或者是使用数据隐藏时使用的.例子: //内部类 class Out{ private int age = 1 ...

  9. vue watch 监听

    1.普通的watch data() { return { frontPoints: 0 } }, watch: { frontPoints(newValue, oldValue) { console. ...

  10. 用navcat编写定时任务调用存储过程

    最近项目需要改动比较大,数据库结构也有所改变,这时就需要转移旧数据到新库中 第一时间想到的是用代码操作,由于两个库表结构不同,实体什么的得需要重新生成 并编写转移代码,这将是很大的工作量: 然后就想着 ...