Cell Phone Network

Cell Phone Network
输入:
5
1 3
5 2
4 3
3 5

输出:
2

说明:
The towers can be placed at pastures 2 and 3 or pastures 3 and 5.

题目大意:
• 给你一棵无向树,问你最少用多少个点可以覆盖掉所有其他的点?
• (一个点被盖,它自己和与它相邻的点都算被覆盖)

思路: 核心:树形dp
树形dp题目一般以结点为根的子树记录状态,设x为结点,结点有三种状态,选、不选但父亲选、不选但儿子选(后面两个情况可以合并),为了清楚分开讨论= =
情况一
结点x选,儿子选和不选都可行,只要选小的值就好
f[x][0]= ∑min(f[son][0], f[son][1],f[son][2])
情况二
x不选,父亲选,儿子没有限制条件,选小的值就好
f[x][2]=∑min(f[son][0],f[son][1])
情况三
x不选,儿子选,稍微有点复杂~
儿子中必须要有一个选的
分两种情况讨论
一、儿子中有一个最小值出现在选的情况下,直接求和最小值
f[x][1]=∑min(f[son][0],f[son][1])
二、所以儿子的最小值都是不选,但必须有一个儿子选,选一个差值最小的最划算
f[x][2]=∑min(f[son][0],f[son][1])+最小差值

//树形dp
//树最小覆盖点
//选f[x][0]=和min(f[son][0],f[son][1],f[son][2])
//不选,儿子选了f[x][1]
//情况一,儿子中有选的,即儿子中存在f[i][0]<=f[i][1]
//情况二,儿子中没选的
//不选,父亲选了f[x][2]=和min(f[son][0],f[son][1])
#include <bits/stdc++.h>
#define IOS std::ios_base::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
using namespace std;
typedef long long ll;
const int N=10000;

int head[N];
int tot=0;
int f[N][3];
int v[N];
struct node
{
    int t,next;
}edge[N*10];
void addedge(int x,int y)
{
    edge[++tot].t=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
void dfs(int x)
{
    v[x]=1;
    bool flag=0;
    int temp=0x7f7f7f7f;
    f[x][0]=1;
    f[x][1]=f[x][2]=0;
    for(int i=head[x] ; i!=0;i=edge[i].next)
    {
        int y=edge[i].t;
        if(v[y]) continue;
        dfs(y);
        f[x][0]+=min(min(f[y][0],f[y][1]),f[y][2]);
        f[x][2]+=min(f[y][0],f[y][1]);
        if( f[y][0]<=f[y][1] )
        {
            flag=1; //存在
            f[x][1]+=f[y][0];
        }
        else
        {
            f[x][1]+=f[y][1];
            temp=min(temp,f[y][0]-f[y][1]);//求最小差值
        }
    }
    if(!flag)    f[x][1]+=temp;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1 ;i<=n-1 ;i++)
    {
        int x,y;
        scanf("%d %d",&x,&y);
        addedge(x,y);
        addedge(y,x);
    }
    dfs(1);
    printf("%d\n",min(f[1][0],f[1][1]));
}
上一篇:2021-03-04js 最新手机号码、电话号码正则表达式


下一篇:phpMyAdmin 4.0.x—4.6.2 远程代码执行漏洞(CVE-2016-5734)