zoukankan      html  css  js  c++  java
  • 树的最小支配集 E

    E - Cell Phone Network

     POJ - 3659 

    题目大意:

    给你一棵树,放置灯塔,每一个节点可以覆盖的范围是这个节点的所有子节点和他的父亲节点,问要使得所有的节点被覆盖的最少灯塔数量。

    考虑每一个节点要被覆盖应该如何放置灯塔。

    如果一个节点被覆盖 1 该节点放了灯塔  2 该点的父亲节点放了灯塔  3 该点的儿子节点放了灯塔。

    dp[u][0] 表示这个节点的儿子节点放了灯塔

    dp[u][1] 表示这个点本身放了灯塔

    dp[u][2] 表示这个点的父亲节点放了灯塔

    转移方程,

    dp[u][1] 可以从儿子的三个状态转移 dp[u][1]=min(dp[v][0],dp[v][1],dp[v][2])

    dp[u][2] 那么如果要儿子节点被覆盖,要么儿子本身有灯塔,要么儿子的儿子有灯塔 dp[u][2]=min(dp[v][0],dp[v][1]) 

    dp[u][0] 这个是这个节点的儿子节点放了灯塔,但是如果这个节点有很多个儿子,我们只要其中一个即可

    所以这个转移比较复杂,可以像之前的 E. Paint the Tree 树形dp 这个一样的去处理。

    不过这个对于子节点选dp[v][1]的限制是只要一个即可,所以可以用一个更简单的方法。

    设置一个变量dif,dif=min(dp[v][1]-dp[v][0],dif)

    最后在加上这个dif即可,其实两个本质上是一样的。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <bitset>
    #include <vector>
    #include <map>
    #include <string>
    #include <cstring>
    #include <bitset>
    #define inf 0x3f3f3f3f
    using namespace std;
    const int maxn=3e5+10;
    typedef long long ll;
    vector<int>G[maxn];
    void add(int u,int v){
        G[u].push_back(v);
        G[v].push_back(u);
    }
    int n;
    void read(){
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
        }
    }
    int dp[maxn][3];
    void dfs(int u,int pre){
        dp[u][0]=0;
        dp[u][1]=1;
        dp[u][2]=0;
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(v==pre) continue;
            dfs(v,u);
            dp[u][1]+=min(dp[v][1],min(dp[v][0],dp[v][2]));
            dp[u][2]+=min(dp[v][1],dp[v][0]);
            dp[u][0]+=dp[v][0];
        }
        vector<int>val;val.clear();
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(v==pre) continue;
            val.push_back(dp[v][1]-dp[v][0]);
        }
        if(val.size()==0) dp[u][0]=inf;
        sort(val.begin(),val.end());
        if(val.size()&&val[0]>0) dp[u][0]+=val[0];
        else {
            for(int i=0;i<val.size();i++){
                if(val[i]>0) break;
                dp[u][0]+=val[i];
            }
        }
        // printf("dp[%d][0]=%d dp[%d][1]=%d dp[%d][2]=%d
    ",u,dp[u][0],u,dp[u][1],u,dp[u][2]);
    }
    
    int main(){
        read();
        dfs(1,-1);
        printf("%d
    ",min(dp[1][0],dp[1][1]));
        return 0;
    }
    View Code

    E. Tree with Small Distances

    题目差不多。

    题目大意:

    给你一棵树,要求这棵树的根节点1 到 每一个点的距离要小于等于2 增加的最少的路数。

    仔细比划比划 就发现和上面是一样的题目。

    只是要标记一下本来就和根节点1 距离小于等于2的所有节点,这些节点的转移有一点不一样,其他都是一样的。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <bitset>
    #include <vector>
    #include <map>
    #include <string>
    #include <cstring>
    #include <bitset>
    #define inf 0x3f3f3f3f
    using namespace std;
    const int maxn=2e5+10;
    typedef long long ll;
    vector<int>G[maxn];
    int vis[maxn];
    void add(int u,int v){
        G[u].push_back(v);
        G[v].push_back(u);
    }
    int n;
    void read(){
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
        }
    }
    int dp[maxn][3];
    void dfs(int u,int pre){
        dp[u][0]=0;
        dp[u][1]=1;
        dp[u][2]=0;
        int dif=inf;
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(v==pre) continue;
            dfs(v,u);
            if(vis[u]){
                dp[u][0]+=min(dp[v][1],dp[v][0]);
                dp[u][1]+=min(dp[v][1],min(dp[v][0],dp[v][2]));
                dp[u][2]+=min(dp[v][1],dp[v][0]);
            }
            else{
                dp[u][1]+=min(dp[v][1],min(dp[v][0],dp[v][2]));
                dp[u][2]+=min(dp[v][1],dp[v][0]);
                dp[u][0]+=min(dp[v][1],dp[v][0]);
                dif=min(dp[v][1]-min(dp[v][1],dp[v][0]),dif);
            }
        }
        if(vis[u]) return ;
        dp[u][0]+=dif;
    }
    
    void init(int u,int pre){
        vis[u]=1;
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            vis[v]=2;
            for(int j=0;j<G[v].size();j++){
                int x=G[v][j];
                vis[x]=3;
            }
        }
    }
    
    int main(){
        read();
        init(1,-1);
        dfs(1,-1);
        printf("%d
    ",min(dp[1][0],dp[1][1]));
        return 0;
    }
    
     
    View Code
  • 相关阅读:
    cmd的操作命令导出导入.dmp文件
    转:String数组初始化
    Oracle计算时间差
    WEB-INF目录与META-INF目录的作用
    【神乎其神】这些EXCEL技巧,太神奇了,赶紧收藏!
    报错: The type ByteInputStream is not accessible due to restriction on required library
    ModelAndView对象作用
    shiro使用
    包装类型的比较,如:Integer,Long,Double
    转一个distinct用法,很有帮助
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/11644524.html
Copyright © 2011-2022 走看看