sgu280:Trade centers(贪心构造)

题目大意:
       给定一棵 n 个结点的树,从中选出一个最小点集S,使得树中每一个点到点集的最小距离 k

分析:
       根据贪心原则,每两个 S 中的点,尽量使得两个点之间的距离=2k+1,因为如果两个点距离 2k+1 ,中间所有的点都是可以覆盖得到的。
       fi 表示 i 到子树中某一个S中的点的距离。
       如果 i 为叶子结点,fi=k+1,表示它只能由 kth ancestor 覆盖 ( 看不懂请往下)
       如果 i 有一个孩子j,那么 fi=fj+1
       如果 i 有两个以上的孩子,那么从孩子中选一个最大的fmax,和最小的 fmin 。如果 fmin+fmax2k+1 ,表示这棵子树中所有的点都可以被覆盖, fi=fmin+1 ,没必要再选根结点;如果 fmin+fmax>2k+1 ,表示这棵子树中所有的点没有都被覆盖,那么这时 fi=fmax+1 。如果 fi=2k+1 ,那么将这个点加入 S 中,fi置为 0
      对于根节点,如果 f1>k 那么也要将其加入 S <script type="math/tex" id="MathJax-Element-37">S</script>中。

AC code:

#include <cstdio>
#include <vector>
#include <algorithm>
#define pb push_back
using namespace std;

const int MAXN = 30009;
const int INF = 0x3f3f3f3f;

int n, k;
int rank[MAXN];
bool is[MAXN];
vector<int> ans;

struct Ugraph
{
    int size;
    int head[MAXN];
    int to[MAXN<<1];
    int ne[MAXN<<1];
    Ugraph() {size = 1;}
    void add_edge(int u, int v)
    {
        to[size] = v, ne[size] = head[u], head[u] = size++;
        to[size] = u, ne[size] = head[v], head[v] = size++;
    }
}G;

void dfs(int x, int fa)
{
    int y, minr = INF, maxr = -INF, c = 0;
    for(int i = G.head[x]; i; i = G.ne[i])
    {
        y = G.to[i];
        if(y != fa)
        {
            dfs(y, x);
            minr = min(minr, rank[y]);
            maxr = max(maxr, rank[y]);
            c++;
        }
    }
    if(!c) rank[x] = k+1;
    else if(c == 1) rank[x] = minr+1;
    else 
    {
        if(minr+maxr+2 <= 2*k+1) rank[x] = minr+1;
        else rank[x] = maxr+1;
    }
    if(rank[x] == 2*k+1) is[x] = true, rank[x] = 0;
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    #endif

    scanf("%d%d", &n, &k);
    for(int i = 1; i < n; ++i)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        G.add_edge(u, v);
    }
    dfs(1, 0);
    for(int i = 1; i <= n; ++i)
        if(is[i] || (i == 1 && rank[i] > k))
            ans.pb(i);
    printf("%d\n", ans.size());
    for(int i = 0, sz = ans.size(); i < sz; ++i)
        printf("%d\n", ans[i]);

    #ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    #endif
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值