Cell Phone Network

来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

Farmer John has decided to give each of his cows a cell phone in hopes
to encourage their social interaction. This, however, requires him to
set up cell phone towers on his N (1 ≤ N ≤ 10,000) pastures
(conveniently numbered 1…N) so they can all communicate. Exactly N-1
pairs of pastures are adjacent, and for any two pastures A and B (1 ≤
A ≤ N; 1 ≤ B ≤ N; A ≠ B) there is a sequence of adjacent pastures such
that A is the first pasture in the sequence and B is the last. Farmer
John can only place cell phone towers in the pastures, and each tower
has enough range to provide service to the pasture it is on and all
pastures adjacent to the pasture with the cell tower. Help him
determine the minimum number of towers he must install to provide cell
phone service to each pasture.

输入描述:

  • Line 1: A single integer: N
  • Lines 2…N: Each line specifies a pair of adjacent pastures with two space-separated integers: A and B
    输出描述:
  • Line 1: A single integer indicating the minimum number of towers to install
    示例1
    输入
    复制
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[x][0]:选点i,并且以点i为根的子树都被覆盖
dp[x][1]:不选i,i被其儿子覆盖
dp[x][2]:不选点i,i被其父亲覆盖(此时儿子可选可不选)
本题和poj1463 NC106060 Strategic game这个题不同的地方在于点i没放兵,但是i的父亲节点放兵,i依旧可以被覆盖

转移方程:
dp[i][0]=1+∑min(dp[u][0],dp[u][1],dp[u][2])(u是i的儿子)
被儿子被自己被父亲覆盖

dp[i][2]=∑(dp[u][1],dp[u][0])
i被父亲覆盖,u是i的儿子,u 可选可不选,但是u肯定不会被i所覆盖

对于dp[i][1]情况,i的儿子们中必须有一个取dp[u][0]
if(i没有子节点)dp[i][1]=INF else dp[i][1]=∑min(dp[u][0],dp[u][1])+inc
对于inc
if(∑min(dp[u][0],dp[u][1])中包含某个dp[u][0])inc=0
else inc=min(dp[u][0]-dp[u][1])
选与不选
图一是自然被选
图二是强制选择
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> pi;
#define debug(a) cout<<#a<<":"<<a<<endl;
#define fr freopen("in.txt","r",stdin);
#define Fill(x,a) memset(x,a,sizeof(x))
#define cpy(a,b) memcpy(a,b,sizeof(a))
const double PI = acos(-1);
const int INF=0x3f3f3f3f;
const int N=1e6+7;
const int mod=1e9+7;
int maxn,minn;
int T,n,m,q;
int head[N];
int cnt;
int dp[N][3];    //0 自身 1 儿子 2 父亲 
struct aa{
    int u,next;
}edge[N];

void init(){
    Fill(head,0);
    cnt=1;
    return ;
}

void add(int u,int v){
    edge[cnt].u=v,edge[cnt].next=head[u];
    head[u]=cnt++;
    return ;
}

void dfs(int u,int p){
    int v,ans=0;
    int a,b,flag;
    flag=INF;
    if(edge[head[u]].next==0&&u!=1){    //叶子节点 
        dp[u][0]=1;
        dp[u][1]=INF;
        dp[u][2]=0;
        return ;
    }
    dp[u][0]=1; 
    for(int i=head[u];i!=0;i=edge[i].next){
        v=edge[i].u;
        if(v==p)    continue;
        dfs(v,u);
        dp[u][0]+=min(dp[v][0],min(dp[v][1],dp[v][2]));
        dp[u][2]+=min(dp[v][1],dp[v][0]);
        ans+=min(dp[v][0],dp[v][1]);
        if(dp[v][0]-dp[v][1]<flag){
            flag=dp[v][0]-dp[v][1];
            a=dp[v][0],b=dp[v][1];
        }
    }
    if(flag>0){
        ans=ans-b+a;
    }
    dp[u][1]=ans;
    return ;
}


int main(){
    int u,v,ans;
    cin>>n;
    init();
    for(int i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    dfs(1,0);
    ans=min(dp[1][0],dp[1][1]);
    cout<<ans<<endl;

    return 0;
}
posted @ 2020-08-28 10:00  回归梦想  阅读(129)  评论(0编辑  收藏  举报