这道题目是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. LPCTSTR和CString的关系

    类型理解 LPCTSTR类型: L表示long指针 这是为了兼容Windows 3.1等16位操作系统遗留下来的,在win32中以及其他的32位操作系统中, long指针和near指针及far修饰符都 ...

  2. 洛谷 P1438 无聊的数列

    题目背景 无聊的YYB总喜欢搞出一些正常人无法搞出的东西.有一天,无聊的YYB想出了一道无聊的题:无聊的数列...(K峰:这题不是傻X题吗) 题目描述 维护一个数列{a[i]},支持两种操作: 1.1 ...

  3. 覆盖alert对话框-自制Jquery.alert插件

    Javascript 代码: (function ($) { 'use strict'; window.alert = $.alert = function (msg) { var defaultOp ...

  4. js 双向绑定

    //双向绑定实例 <input name="" ng-bind-123="name" /> function DataBinder( object_ ...

  5. this+call、apply、bind的区别与使用

    http://www.ruanyifeng.com/blog/2018/06/javascript-this.html https://segmentfault.com/a/1190000018017 ...

  6. Vue的elementUI实现自定义主题

    使用vue开发项目,用到elementUI,根据官网的写法,我们可以自定义主题来适应我们的项目要求,下面来介绍一下两种方法实现的具体步骤,(可以参考官方文档自定义主题官方文档),先说项目中没有使用sc ...

  7. iOS HmacSHA1加密 和 MD5 Base64加密 --iOS开发系列---项目中成长的知识五

    项目中开发中需要对一些数据进行加密后和服务器验证是否是我们客户端发出的请求! 方案是服务器定的,使用HmacSHA1加密和MD5 Base64加密 加密过程比较复杂 1.获取格林威治时间 2.用bas ...

  8. MAC的睡眠模式介绍

    因为之前用的是网上流传的土法来禁止生成 sleepimage,尝到了苦头,而且2次! 大家知道 OSX 有几种睡眠模式,其中 hibernatemode 可以是 0 (传统睡眠方式,不生成 sleep ...

  9. Swift 编程思想 Part 4:map all the things!

    Swift 编程思想 Part 4:map all the things! 2015-10-22  837 文章目录 1. 数组 vs. 可选类型 2. 作用在可选类型上的 map() 3. 回到我们 ...

  10. Fortran学习笔记6(函数、子程序)

    子程序Subroutine 自定义函数Function 全局变量COMMON BLOCK DATA 程序代码中,常常会在不同的地方重复用到某一功能和重复某一代码,这个时候就要使用函数.函数包括内嵌函数 ...