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


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

    求最小扩展数,

    准备想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
    ",min_ans);
        
        return 0;
    }
    View Code
  • 相关阅读:
    使用ALAssetsLibrary读取所有照片
    dispatch_after中时间的计算
    UICollectionView的header悬停
    ios侧滑返回:完美解决 interactivePopGestureRecognizer 卡住的问题
    自定义TabBar
    automaticallyAdjustsScrollViewInsets(UITextView文字顶部留有空白)
    kvo&kvc
    调用iPhone的短信
    Windows 10中Oracle数据库导出到Access数据库(MDB)
    HP Z620 Windows 7 系统安装(含磁盘阵列)
  • 原文地址:https://www.cnblogs.com/xwww666666/p/11771000.html
Copyright © 2020-2023  润新知