题解 P1041 【传染病控制】

· · 题解

一. 题目大意

二. 错误做法

三. 具体思路

我们看一下数据范围: n <=300,所以这棵树最多只有300层(一条链),就可以用大暴搜了qwq!!!

  1. 建树.这个没啥好说的qwq.

  2. 预处理出来每个节点的深度,记录每一层节点.

  3. 预处理出来子树大小.

  4. 从第一层节点开始DFS,枚举下一层的节点,分别把这条相连的边剪掉,把整个子树标记为已经控制,DFS下一层,回溯时更新答案即可.

注意:如果某一层的边全部剪掉的话,那么就到达不了下一层了,即为最终状态,直接更新 ans 即可.

四. 代码

下面是代码:

#include<iostream>

#define N 310

using namespace std;

int count[N],deep[N][N],vis[N];
int n,p,maxx,ans=310;
struct Node
{
    int num,son[N];
}tree[N];

void Deep(int x,int dp)
{
    maxx=max(maxx,dp);//记录最深层
    for(int i=1;i<=tree[x].num;i++)
    {
        int y=tree[x].son[i];
        deep[dp][++deep[dp][0]]=y;//记录当层节点
        Deep(y,dp+1);//下一层
    }
}

int Size(int x)
{
    if(!tree[x].num)  return 1;//子树大小为一
    for(int i=1;i<=tree[x].num;i++)
    count[x]+=Size(tree[x].son[i]);//加上大小
    return count[x];
}

void Cover(int x,int y)//y=1为已经安全,0则为还有危险
{
    vis[x]=y;//标记
    for(int i=1;i<=tree[x].num;i++)
    Cover(tree[x].son[i],y);
}

void DFS(int now,int per)
{
    if(now==maxx)
    {
        ans=min(ans,per);
        return;
    }//更新答案
    int vi=0;
    for(int i=1;i<=deep[now][0];i++)
    {
        int x=deep[now][i];
        if(vis[x])//已经安全
        {
            vi++;continue;
        } 
        Cover(x,1);
        DFS(now+1,per-count[x]);
        Cover(x,0);//回溯
    }
    if(vi==deep[now][0])  ans=min(ans,per);
}

int main()
{
    cin>>n>>p;int x,y;
    for(int i=1;i<=n;i++)  count[i]=1;
    for(int i=1;i<=p;i++)
    {
        cin>>x>>y;
        if(x>y)  swap(x,y);
        tree[x].son[++tree[x].num]=y;
    }//建树
    Deep(1,2);
    Size(1);
    DFS(2,n);
    cout<<ans<<endl;
    return 0;
}

如果觉得有帮助的话别忘了给可爱的up主三连点赞哦qwq.

Update on 2019.10.25 举了反例,希望管理员给过.

猪突猛进!!!

Plus Ultra!