HDOJ 4582: DFS spanning tree

原创 2013年08月12日 12:50:36

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4582



题目大意:
给出一个没有自环的有向图。
这个图的前n-1条边构成这个图的一个以节点1为根节点的DFS树。
T-Simple环的定义是:至多有一条边不在这棵DFS树上的环。

问,至少在图上选中多少条边。才使得每个T-simple环都至少有一条边被选中。


算法:

需注意的是,题目给出的是一个无向图的DFS树,

所以不在这棵树上的边一定不可能是"横叉边",而一定是" 后向边(返祖边)"。

也就是说,不在DFS树上的边,一定是由某点指向它的某个祖先的。

很容易想象,如果不是这样,那么DFS树的形态一定会发生改变。(学过tarjan的人应该都能理解吧)


由于T-Simple环的定义要求至多有一条边不在DFS树上,

我们不妨枚举这条不在DFS树的边。

也就是对于每条不在DFS树上的边,

它连接了树上的某个点和它的某个祖先。

这两点间的树上路径以及这条不在DFS树的边,构成了一个T-simple环。

那么,这题的模型就可以抽象成。

给出一棵树,再给出若干限制。

每个限制指定一个点,以及它的一个祖先。

要求这个点到这个祖先的路径上,至少有一条边被选中。

问至少选中多少条边。

树形DP的模型也就很明显了。


我用lim[u]表示,u这个点,与它有非树边相连的祖先节点中,离它最近的那个的深度是多少。

如果u这个点没有任何通过非树边与祖先相连,那么lim[u]=0。

因为lim[u]=x表示,点x到点u的路径上,至少有一个点,它连向父节点的那条边要被选中。

不过节点0根本就没有父节点(我的节点是以0~n-1计数的),所以lim[u]=0代表没有边必须被选中

(如果不能理解的话,可以假想节点0到它到“父节点”的边被选中了,不过在计数的时候没把这条边算进去)。


d[u][x]表示,如果根到u的路径上离u最近的一条被选中的边,是由深度为x的点指向它的父节点的,那么以u为根的子树中至少要选中多少边。

于是就是一个很明了的自下向上更新的树形DP了。

显然,只有对于lim[u]<=k<=dep[u]的k,d[u][k]才是合法的。

要计算d[u][k]时,对于u的每个子节点v,

应该从d[v][0]~d[v][k]以及d[v][dep[v]]中,选取一个合法的最小值,

再把这些最小值加起来。

另外,对于dep[u][dep[u]],应该再加上1,代表u指向根节点的那条边被选中了。


最后,d[0][0]的值即为所求。


PS:因为最近看到别人抱怨大家给的题解太简单,所以特意写的详细些。如果再看不懂。。。那就来问我吧 T^T

PPS:如果想了解这道题的贪心解法可以看sd6001大牛的解题报告


代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <climits>
#include <cmath>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;

const int MAXN = 2100;
vector<int> mm[MAXN];
int dep[MAXN], lim[MAXN];
int d[MAXN][MAXN];

void dfs(int u, int p)
{
    for (int i = 0; i < mm[u].size(); i ++)
    {
        int v = mm[u][i];
        if (v == p)
        {
            continue;
        }
        dep[v] = dep[u] + 1;
        dfs(v, u);
    }
}

void dp(int u, int p)
{
    for (int i = lim[u]; i <= dep[u]; i ++)
    {
        d[u][i] = 0;
    }
    for (int i = 0; i < mm[u].size(); i ++)
    {
        int v = mm[u][i];
        if (v == p)
        {
            continue;
        }
        dp(v, u);
        int tmp = d[v][dep[v]];
        for (int k = 0; k <= dep[u]; k ++)
        {
            if (d[v][k] != -1)
            {
                tmp = (tmp == -1) ? d[v][k] : min(tmp, d[v][k]);
            }
            if (k >= lim[u])
            {
                d[u][k] += tmp;
            }
        }
    }
    if (p != -1)
    {
        d[u][dep[u]] ++;
    }
}

int main()
{
    int n, m;
    while (scanf("%d %d", &n, &m), n || m)
    {
        memset(d, -1, sizeof(d));
        memset(lim, 0, sizeof(lim));
        memset(dep, -1, sizeof(dep));
        for (int i = 0; i < n; i ++)
        {
            mm[i].clear();
        }
        for (int i = 1; i < n; i ++)
        {
            int u, v;
            scanf("%d %d", &u, &v);
            u --;
            v --;
            mm[u].push_back(v);
            mm[v].push_back(u);
        }
        dep[0] = 0;
        dfs(0, -1);
        for (int i = n; i <= m; i ++)
        {
            int u, v;
            scanf("%d %d", &u, &v);
            u --;
            v --;
            if (dep[u] < dep[v])
            {
                swap(u, v);
            }
            lim[u] = max(lim[u], dep[v] + 1);
        }
        dp(0, -1);
        printf("%d\n", d[0][0]);
    }
    return 0;
}


让我们来谈谈最小生成树(Minimum Spanning Tree)算法

现实生活中我们往往会遇到类似于旅游路线规划,使用怎么样的一条旅游路线能够让我们花费最少的旅费获得一样的感受。这时如果你学过算法的话,恭喜你可以在女票面前大显生手了。这其实是一个最小生成树问题,可以利用...
  • shaya118
  • shaya118
  • 2014年12月24日 21:34
  • 2166

说说最小生成树(Minimum Spanning Tree)

minimum spanning tree(MST) 最小生成树是连通无向带权图的一个子图,要求 能够连接图中的所有顶点、无环、路径的权重和为所有路径中最小的. graph-cut 对图的一个...
  • gsky1986
  • gsky1986
  • 2015年04月20日 14:24
  • 2303

poj1679 The Unique MST(判定次小生成树)

The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 23180  ...
  • su20145104009
  • su20145104009
  • 2015年07月20日 08:44
  • 1778

HDU 4582 DFS spanning tree 解题报告(贪心 & 树形DP)

首先声明,这题我是不会的,参考了frog1902的解题报告。http://blog.csdn.net/frog1902/article/details/9921845     当然,她的解题报告一开始...
  • kbdwo
  • kbdwo
  • 2013年08月15日 17:41
  • 1222

hdoj 4408 Minimum Spanning Tree 求最小生成树的数目

最小生成树计数-Kruskal+Matrix_Tree定理 基本介绍 给定一个含有N个结点M条边的无向图,求它最小生成树的个数t(G); 算法思想 抛开“最小”的限制不看,如果只要求求出所有...
  • zyf_2014
  • zyf_2014
  • 2016年10月25日 20:07
  • 192

【Wunder Fund Round 2016 (Div 1 + Div 2 combined)D】【贪心 dfs】Hamiltonian Spanning Tree 树的最小链划分

D. Hamiltonian Spanning Tree time limit per test 2 seconds memory limit per test 256 meg...
  • snowy_smile
  • snowy_smile
  • 2016年03月01日 18:13
  • 518

dfs枚举 + 最小生成树 hdoj2489 Minimal Ratio Tree

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2489题目大意是,给你一个图,这个图不仅有边权,还有点权,图中共有n个点,问做一棵包含m个结点的生成树...
  • jlu_nnbs
  • jlu_nnbs
  • 2017年05月21日 17:48
  • 89

spanning tree

  • 2011年10月30日 20:47
  • 16.9MB
  • 下载

Spanning_Tree

  • 2011年10月25日 22:30
  • 1.64MB
  • 下载

DES-3226S配置Spanning tree

  • 2012年11月04日 16:06
  • 386KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:HDOJ 4582: DFS spanning tree
举报原因:
原因补充:

(最多只允许输入30个字)