zoukankan      html  css  js  c++  java
  • CF E .Tree with Small Distances(树上的贪心)

    题意

    这是一颗有n-1条边的无向树 , 在树上加最少的边使树的1节点到其他节点的距离最多为 2 ;

    分析:很容易考虑的贪心的做法,但是该如何的贪心呢 ? 我一开始是打算贪心节点的儿子最多那一个 , 但这样是不行的,举个反例子例:1-2 ; 2-3 ; 3-4 ; 3-5 ; 3-6 ; 3-7 ; 4-8 ; 4-9 ; 5-10 ; 5-11 ; 6-12 ; 6-13 ; 7-14 ; 7-15 ; 可自己做出图,按这样的贪心出来的结果是5 ; 结果是4,所以这样的贪心是不行的 ; 我们在考虑其他的贪心做法;

    我们可以来思考一下,能拿什么来贪心,节点度数,节点距顶点1的距离,节点的儿子数,节点的父节点,总共也就这么几个指标,可以进行排除法。

         因此可以发现度数、儿子数、节点数都不可以,因为没有办法满足当前最优,但是距离是可以的,因为离节点1越远的点越难通过加边到达,因此应该按照距离进行贪心,然后就又出现了一个问题。

         很多人进行到这步之后,就会理所当然的认为找到距离最远的点,然后让节点1和该点连一条边,然后很自然地就wa了...

         仔细思考一下,找到这个点之后,应该和谁连边,是和该节点的儿子、父亲还是节点本身,儿子显然不成立,如果和父亲连边显然比本身更优,因此题目就可以解决了。

    为什么呢? 我们是贪心出距离最长的节点优先考虑连边,故是从下肉上递推 ,而最长的节点一定是树的根节点,故连接该节点的父亲节点所得出来的贡献更大:

    #include<bits/stdc++.h>
    using namespace std;
    int n ;
    priority_queue<pair<int , int > > q;
    vector<int>G[200001];
    bool book[200001];
    int per[200001],dis[200001];
    void init( )
    {
        for(int i=1 ; i<=n ; i++)
        book[i]=0;
        for(int i=1 ; i<=n ; i++)
        G[i].clear();
        while(q.size())
        q.pop();
    }
    void dfs(int cur , int fa)
    {
        per[cur] = fa ;
        for(int i=0 ; i<G[cur].size() ; i++)
        {
            int v = G[cur][i] ;
            if(v==fa)
            continue ;
            dis[v] = dis[cur] + 1 ;
            if(dis[v]>2)
            q.push(make_pair(dis[v],v));
            else
            book[v]=1;
            dfs(v,cur);
        }
    }
    
    int main( )
    {
    
        scanf("%d",&n);
        for(int i=1 ; i<=n-1 ; i++)
        {
            int u,v ;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1,-1);
        int ans=0;
        while(q.size())
        {
            int v = q.top().second;q.pop();
            if(book[v]==1)
            continue;
            int fa=per[v];
            book[fa]=1;
            ans++;
            printf("%d %d
    ",v,fa);
            for(int i=0 ; i<G[fa].size() ; i++)
            {
                int cur = G[fa][i];
                book[cur]=1;
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    Python网络爬虫第三弹《爬取get请求的页面数据》
    18.增量式爬虫
    17.基于scrapy-redis两种形式的分布式爬虫
    关于进程内存磁盘的一些命令
    linux其他命令
    ls -用于显示指定工作目录下之内容(列出目前工作目录所含之文件及子目录)
    mkdir和touch
    ls -列出当前目录下所有的文件或者目录
    cat -用于连接文件并打印到标准输出设备上
    rm -移动文件
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/9542072.html
Copyright © 2011-2022 走看看