zoukankan      html  css  js  c++  java
  • 最小驻扎问题

    这个问题是我乱命名的

    最小驻扎指的是:

    图上每个点,可以付出代价并对其周围一定距离的点产生影响。

    求最小的驻扎量,使得所有的点受影响。

    又强行编了个定义

    解决这类问题的方法,我知道两种

    • 动态规划
    • 贪心

    DP太难了我不会,我只会贪心。

    直接讲难的吧(反正简单的改一下就可以了

    点我飞去luogu

    狗屎测试题。

    先讲思路(我抄袭的,from zt

    对于最深的点,要想让它被控制,最优(不仅控制它,还可以控制尽量多的其他点)的方案一定是它的第k父亲。

    以深度排序,从最深的开始检查:如果该点没有被控制,就在它的第k父亲放军队,并更新第k父亲可以影响到的点的状态。

    虽然很暴力,但这是对的。

    大家颅内证明一下

    #include<iostream>
    #include<algorithm>
    #include<vector>
    using namespace std;
    int n,k,t;
    vector <int> map[100001];//存图
    struct yi//存点
    {
        int posi;//点的编号
        int deep;//点的深度
        friend bool operator < (const yi &a,const yi &b)
        {
            return a.deep>b.deep;//重载 < 排序用
        }
    }point[100001];//也可以写node[100001];
    bool vis[100001];//是否访问过
    int shen[100001];//存编号i的深度。和point[].deep一样,但这个从1~n方便用。
    void dfs(int x,int d)//dfs求深度。x表示当前点,d表示当前点深度
    {
        vis[x]=1;//标记,访问过了
        point[x].posi=x,point[x].deep=d;//存下编号及深度
        for(unsigned int i=0;i<map[x].size();i++)
            if(!vis[map[x][i]])//避免重复求
                dfs(map[x][i],d+1);
    }
    bool control[100001];//是否被控制
    bool cmp1(const int &a,const int &b)
    {
        return shen[a]<shen[b];//find()排序用的比较
    }
    inline int find(int x,int d)//查找最深节点的第k父亲。d最开始调用为k,不断-1,=0时走到第k父亲
    {
        if(!d)
            return x;
        vis[x]=1;
        sort(map[x].begin(),map[x].end(),cmp1);//排序,原因请下拉
        for(unsigned int i=0;i<map[x].size();i++)
            if(!vis[map[x][i]])
                return find(map[x][i],d-1);//dfs找下去
        return x;//找不到,即没有第k父亲,只有第k-1父亲或k-2或...,返回本节点代替第k父亲
    }
    inline void change(int x,int d)//改变可影响到的节点的状态control[]
    {
        control[x]=1;//已控制
        if(!d)//d递减进行dfs
            return ;
        vis[x]=1;//标记访问过
        for(unsigned int i=0;i<map[x].size();i++)
            if(!vis[map[x][i]])
                change(map[x][i],d-1);
    }
    int main()
    {
        in(n);in(k);in(t);
        if(k==0)//特别判断垃圾情况,k==0每个点只能控制自己
        {
            cout<<n;
            return 0;
        }
        int ans=0;
        for(int i=1;i<n;i++)
        {
            int x,y;
            in(x);in(y);
            map[x].push_back(y);
            map[y].push_back(x);//vector最高
        }
        dfs((1+n)>>1,1);//求深度的起点可以随意,我选择(1+n)>>1
        sort(point+1,point+n+1);//从1开始存的
        for(int i=1;i<=n;i++)
            shen[point[i].posi]=point[i].deep;//预先用shen[]存好节点深度,方便找 排序
        for(int i=1;i<=n;i++)
            if(!control[point[i].posi])//如果当前最深点没被控制
            {
                memset(vis,0,sizeof(vis));//初始化
                int dad=find(point[i].posi,k);//找第k父亲。懒得想变量名,直接dad
                memset(vis,0,sizeof(vis));//初始化
                change(dad,k);//更新状态
                ans++;//更新答案
            }
        cout<<ans;
        return 0;
    }
    

    sort的原因

    bool cmp1(const int &a,const int &b)
    {
        return shen[a]<shen[b];
    }
    inline int find(int x,int d)
    {
        if(!d)
            return x;
        vis[x]=1;
        sort(map[x].begin(),map[x].end(),cmp1);
        for(unsigned int i=0;i<map[x].size();i++)
            if(!vis[map[x][i]])
                return find(map[x][i],d-1);
        return x;
    }
    

    我们从最深的节点开始找第k父亲。但在树上(这题),一个点的第k父亲,可能不止一个,我们只选择最优的贪心。最优的第k父亲,一定是深度最小的第k父亲。因为贪心的目的就是由深到浅进行控制,越早控制浅的就越优,所以进行排序,对深度最浅的进行dfs找第k父亲。

    然后就A啦。

    视奸dalao的不同写法的代码

    huangwenlong,huangwenlong

    Toby_ZT

    mnyhome

    还有好多,全部放下来的话下拉体验很差

    修改一下输入方法,这题也轻松A

  • 相关阅读:
    Django Form组件的扩展
    Python TCP与UDP的区别
    Python三次握手和四次挥手
    网络基础之网络协议
    Python 类方法、实例方法、静态方法的使用与及实例
    python深浅拷贝
    2021牛客寒假算法基础集训营1 题解
    01 Trie 专题
    MOTS:多目标跟踪和分割论文翻译
    牛客巅峰赛S2第6场题解
  • 原文地址:https://www.cnblogs.com/syhien/p/7777255.html
Copyright © 2011-2022 走看看