Page 1 of 131234567810...Last »

pku 1947 Rebuilding Roads

Pku, USACO 3 Comments »358 views

这是一个孩子之间有分配的树形动态规划问题,一般解决的方法为左孩子右兄弟法或孩子背包分配。

左孩子右兄弟表示法中,状态设定为

F[i,j]表示以i为根的子树以及以i右边兄弟为根的子树中选j个点需要删除边的最少数量。F[i,j]还隐含了i的父亲已经被选,否则i是不可能被选的。

状态转移方程为

F[i][j] = Min
{
F[i.brother][j] + 1 (不选节点i)
F[i.child][k] + F[i.brother][j-k-1] (选节点i) 0<=k<=i子树及兄弟子树大小-1 且 k<=j-1
}

边界条件

F[i][0] = F[i.brother][0] + 1
节点0为一个虚构的节点,如果节点i没有兄弟(或儿子),则它的兄弟(或儿子)为0。
F[0][0]=0
F[0][j]=INF (j>0,INF为一个极大的值)

目标状态

左孩子右兄弟表示法的目标状态表示不很直观,一棵子树分配P个节点,需要表示成子树根第一个孩子及其兄弟分配P-1的节点。另外,如果不是根节点,还要增加1,表示与它的父节点的边也断掉。
Ans = Min{ F[根节点的第一个孩子][P-1] , F[非根节点的第一个孩子][P-1] + 1 }

如果用孩子背包分配法,状态可以表示为

F[i][j]为以i为根的子树中选择j个节点要删除边的最少数量。

状态转移方程为

F[i][j] = Min { Sigma{ F[i.child[k]][m[k]] } } 其中 sigma[m[k]] = j-1
直接在孩子中分配不易,需要再进行一次DP,运用背包的思想,设状态

G[a][b]为对于特定的i时i的前i个孩子分配j个节点的最小值

G[a][b] = Min { G[a-1][b-k] + F[i.child[a]][k] }

于是F[i][j]可以表示为 F[i][j] = G[i.childcount][j-1]

边界条件为

对于每个节点i
G[0][0]=0
G[0][j]=INF (j>0 INF为一个极大的值)

当i为叶节点时
F[i][0]=1
F[i][1]=0

目标状态

Ans = Min{ F[根节点][P] , F[非根节点][P] + 1}

对于这道题,两种方法的时间复杂度均为O(N^3)。左孩子右兄弟法的优点在于状态转移比较简单,缺点是不够直观,尤其在表示目标状态的时候,另外边界情况的考虑也比较复杂,还有就是需要额外建树。孩子背包分配的方法优点是状态直观,易于表示,容易写成非递归,缺点是状态转移较为复杂,需要用一个背包再分配一次。我个人比较倾向于孩子背包分配法,除非必须,我一般都会写成这样的。

Read the rest of this entry »

标签:, ,

pku 1743 Musical Theme

Pku, USACO 2 Comments »254 views

把原序列相邻每项做差,然后问题就转化成了求一个串的最长不重叠重复子串,且两个子串相距至少一位,可以用后缀数组做。

首先求出后缀数组和Height数组,Height[i]=LCP(SA[i],SA[i-1])。接下来二分答案A,判定A是否为可行解。判断方法是找出在Height数组中找出连续的一段Height[i..j],使得i<=k<=j均满足Height[k]>=A,并且i-1<=k1,k2<=j中,要有Max{SA[k1]} – Min{SA[k2]} >= A + 1(距离相差至少1),这时A是可行的。

后缀数组的分组思想十分重要,这道题就是一个经典应用,还应用到了求最长公共子串(LCS)问题。
Read the rest of this entry »

标签:, ,

pku 3255 Roadblocks

Pku, USACO No Comments »306 views

这道题不同于一般的次短路径问题,因为允许边重走。看似更为复杂了,其实是更简单了一些。方法为先用Heap+Dijkstra求出1和N的单源最短路径,把无向边看成两个有向边,然后枚举每单向条边(u,v),计算Dist=dis(1,u) + dis(N,v),看看此时Dist的值是否大于dis(1,N),如果是的话用它更新次短路径,保留一个最小的值。

USACO 2006 November Gold

Read the rest of this entry »

标签:, , ,

pku 3177 (3352) Redundant Paths

Pku, USACO 5 Comments »589 views

题目大意是,给定一个连通图,要求添加一些边,使每两个顶点之间都有至少两条不相交的路径,求最小需要添加的边数。

很显然,题中要求的图就是一个边双连通图,即边连通度不小于2。我的方法是在原图中DFS求出所有的桥,然后删除这些桥边,剩下的每个连通块都是一个双连通子图。把每个双连通子图收缩为一个顶点,再把桥边加回来,最后的这个图一定是一棵树,边连通度为1。统计出树中度为1的节点的个数,即为叶节点的个数,记为leaf。有人说至少在树上添加(leaf+1)/2条边,就能使树达到边二连通,所以结果就是(leaf+1)/2。

这个结论我不能证明,但是可以想象出是对的。简单说明一下,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。

这道题跟pku3352一模一样,拿这个程序交两个题一个字不用改都能AC!但实际上两个题也稍有不同,这个题有一点很不容易被注意到,就是可能存在重边,两个点之间如果存在有重边,也算是双连通的。我的处理方法是在DFS时标记每条边及其反向边是否被访问过,而不是判断顶点。

Read the rest of this entry »

标签:, , ,

USACO FEB07 Silver Silver Lilypad Pond 银色莲花池

USACO No Comments »324 views

Read the rest of this entry »

标签:, , ,
24 queries. 0.858 seconds. Designed by NattyWP .
Images by desEXign.