树上最小边覆盖问题

Posted jjl0229

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树上最小边覆盖问题相关的知识,希望对你有一定的参考价值。

1077. 皇宫看守

鲍勃喜欢玩电脑游戏,特别是战略游戏,但有时他找不到解决问题的方法,这让他很伤心。
现在他有以下问题。
他必须保护一座中世纪城市,这条城市的道路构成了一棵树。
每个节点上的士兵可以观察到所有和这个点相连的边。
他必须在节点上放置最少数量的士兵,以便他们可以观察到所有的边。
你能帮助他吗?
例如,下面的树:
技术图片
只需要放置1名士兵(在节点1处),就可观察到所有的边。
输入格式
输入包含多组测试数据,每组测试数据用以描述一棵树。
对于每组测试数据,第一行包含整数N,表示树的节点数目。
接下来N行,每行按如下方法描述一个节点。
节点编号:(子节点数目) 子节点 子节点 …
节点编号从0到N-1,每个节点的子节点数量均不超过10,每个边在输入数据中只出现一次。
输出格式
对于每组测试数据,输出一个占据一行的结果,表示最少需要的士兵数。
数据范围
0<N≤1500
输入样例:
4
0:(1) 1
1:(2) 2 3
2:(0)
3:(0)
5
3:(3) 1 4 2
1:(1) 0
2:(0)
0:(0)
4:(0)
输出样例:
1
2

对于一条边,可以由父节点覆盖,或者子节点覆盖,f[u][0]表示该节点不放士兵,f[u][1]表示该节点放士兵.
当该节点不放时,只有由所有子节点放的情况转移;当该节点放时,可以由子节点放或不放的情况转移而来

#include<bits/stdc++.h>
using namespace std;
const int N=1510;
int h[N],idx,f[N][2];//0不放,1放
struct eg{
    int v,nex;
}e[N*2];
void add(int u,int v){
    e[idx]={v,h[u]};
    h[u]=idx++;
}
void dfs(int u,int pre){
    f[u][1]=1;
    f[u][0]=0;
    for(int i=h[u];~i;i=e[i].nex){
        int v=e[i].v;
        if(pre==v) continue;
        dfs(v,u);
        f[u][0]+=f[v][1];
        f[u][1]+=min(f[v][1],f[v][0]);
    }
}
int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        memset(h,-1 ,sizeof h); idx=0;
        for(int i=1;i<=n;++i){
            int u,k,v;
            scanf("%d:(%d)",&u,&k);
            while(k--){
                scanf("%d",&v);
                add(u,v);
                add(v,u);
            }
        }
        dfs(0,-1);
        if(n==1) cout<<1<<endl;
        else 
        cout<<min(f[0][1],f[0][0])<<endl;
    }
    return 0;
}

以上是关于树上最小边覆盖问题的主要内容,如果未能解决你的问题,请参考以下文章

9.21 生成树

二分图中对最小顶点覆盖最小边覆盖最大独立集的理解[转]

Prim算法与Kruskal(没有代码)

[LCA 树上差分边差分] 闇の連鎖

P2764 最小路径覆盖问题 网络流输出方案

HDU 4582 DFS spanning tree