luogu#P2016 战略游戏

题意:

给出一棵有 \(N\) 个节点的树,节点编号 \(0\) ~ \(N-1\) 。如果在一个节点上放置一个士兵,那么该节点及与该节点相连的所有节点都可以被瞭望到。求瞭望到所有节点所需的最少的士兵数。

解法:

树形dp

\(f[i][j]\) = 节点 \(i\) 选(\(j=1\))不选(\(j=0\))的最少需要的士兵

因为对于一个节点 \(i\) ,如果它不选,那么必须选与它相连的点的其中一个,则:

f[x][1]+=min(f[v][0],f[v][1]); //设v是与x相邻的点
f[x][0]+=f[v][1];

因为没有给出树根,所以要手动求出。

感觉跟没有舞会的上司差不多,居然还是一道蓝题

#include<iostream>
#define N 1505
using namespace std;
struct Edge{int next,to;}edge[N<<1];
int n_e,head[N],n,root;
int f[N][2];
bool rt[N];

void dp(int x);
void addedge(int from,int to);
void init();
int main()
{
    init();
    dp(root);
    cout<<min(f[root][1],f[root][0]);
    
    return 0;
}
void init()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int id,num,v;
        cin>>id>>num;
        f[i][1]=1;
        for(int j=0;j<num;j++)
        {
            cin>>v;
            rt[v]=1;
            addedge(id,v);
        }
    }
    for(int i=0;i<n;i++)
        if(!rt[i])
        {
            root=i;
            break;
        }
}
void addedge(int from,int to)
{
    edge[++n_e].next=head[from];
    edge[n_e].to=to;
    head[from]=n_e;
}
void dp(int x)
{
    for(int i=head[x];i;i=edge[i].next)
    {
        int v=edge[i].to;
        dp(v);
        f[x][1]+=min(f[v][1],f[v][0]);
        f[x][0]+=f[v][1];
    }   
}

猜你喜欢

转载自www.cnblogs.com/nenT/p/11716605.html