【刷题】【树上搜索】传染病控制

时间:2019-10-31
本文章向大家介绍【刷题】【树上搜索】传染病控制,主要包括【刷题】【树上搜索】传染病控制使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一个比较奇怪的情况,每次砍掉一颗子树,其他会拓展,

求最小扩展数,

准备想dp,但是仔细看一下这个过程,

在某一阶段,我有dep_sz[nw]个点会继续扩展,其他的被砍了,

然后我挑一个点隔离,其他的还是继续扩展,

这里的哪个点怎么挑呢?

与子树节点和有关?贪心选择son_sz最大的点,会wa,因为还有一个g_sz变量

而且每次隔离这个点后,这个点的son_sz都没了,

但是受影响的是他的兄弟,

并且兄弟的情况会变得很复杂......

有下一层隔断的,下下层隔断的,时间各不相同

但是我们可以从上面的思路中,发现,

我们总共会隔离最多mx_dep次,

并且,第i次,隔离的必定为dep==i+1次(root的深度为1)

每次被隔离的其实不多,更多的是还在感染的,

这样dp其实反而效率不高,搜索更快

所以就以dep为阶段,搜索

注意标记的过程,这样最快,取消也最容易,但是前一种写法是错的

void dfs_0(int rt,int dp)
{
    sz[rt]=1;
    dep[dp].push_back(rt),dep_sz[dp]++;
    g_sz[rt]=g[rt].size() ;
    
    for(int i=0;i<g_sz[rt];i++)
        if(g[rt][i]!=fa[rt])
        {
            fa[g[rt][i]]=rt;
            dfs_0(g[rt][i],dp+1);
            sz[rt]+=sz[g[rt][i]];
        }
}
void dfs(int dp,int ans)
{    
    int res=dep_sz[dp];
    for(int i=0;i<dep_sz[dp];i++)
    {
        int rt=dep[dp][i];
        if(vis[fa[rt]])
        {
            res--;
            vis[rt]=true;
        }
        else vis[rt]=false;
    }
    
    if(!res)
        min_ans=min(min_ans,ans);
    else for(int i=0;i<dep_sz[dp];i++)
    {
        int rt=dep[dp][i];
        if(!vis[rt])
        {
            vis[rt]=true;
            dfs(dp+1,ans-sz[rt]);
            vis[rt]=false;
        }
    }
}

全部代码:

#include<cstdio>
#include<cstdlib>
#include<vector>
using namespace std;
int n,m;
const int N=303;
vector <int> g[N],dep[N]; 
int g_sz[N],dep_sz[N];
int sz[N],fa[N];

void dfs_0(int rt,int dp)
{
    sz[rt]=1;
    dep[dp].push_back(rt),dep_sz[dp]++;
    g_sz[rt]=g[rt].size() ;
    
    for(int i=0;i<g_sz[rt];i++)
        if(g[rt][i]!=fa[rt])
        {
            fa[g[rt][i]]=rt;
            dfs_0(g[rt][i],dp+1);
            sz[rt]+=sz[g[rt][i]];
        }
}
int min_ans;
bool vis[N];
void dfs(int dp,int ans)
{    
    int res=dep_sz[dp];
    for(int i=0;i<dep_sz[dp];i++)
    {
        int rt=dep[dp][i];
        if(vis[fa[rt]])
        {
            res--;
            vis[rt]=true;
        }
        else vis[rt]=false;
    }
    
    if(!res)
        min_ans=min(min_ans,ans);
    else for(int i=0;i<dep_sz[dp];i++)
    {
        int rt=dep[dp][i];
        if(!vis[rt])
        {
            vis[rt]=true;
            dfs(dp+1,ans-sz[rt]);
            vis[rt]=false;
        }
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        g[u].push_back(v),g[v].push_back(u);  
    }
    dfs_0(1,1);
    
    min_ans=n-1;
    dfs(2,n);
    
    for(int i=2;i<=n;i++)
        if(!sz[i]) min_ans--;
    printf("%d\n",min_ans);
    
    return 0;
}
View Code

原文地址:https://www.cnblogs.com/xwww666666/p/11771000.html