zoukankan      html  css  js  c++  java
  • P1272 重建道路(树形dp)

    P1272 重建道路

    题目描述

    一场可怕的地震后,人们用N个牲口棚(1≤N≤150,编号1..N)重建了农夫John的牧场。由于人们没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是惟一的。因此,牧场运输系统可以被构建成一棵树。John想要知道另一次地震会造成多严重的破坏。有些道路一旦被毁坏,就会使一棵含有P(1≤P≤N)个牲口棚的子树和剩余的牲口棚分离,John想知道这些道路的最小数目。

    输入输出格式

    输入格式:

    第1行:2个整数,N和P

    第2..N行:每行2个整数I和J,表示节点I是节点J的父节点。

    输出格式:

    单独一行,包含一旦被破坏将分离出恰含P个节点的子树的道路的最小数目。

    输入输出样例

    输入样例#1:
    11 6
    1 2
    1 3
    1 4
    1 5
    2 6
    2 7
    2 8
    4 9
    4 10
    4 11
    
    输出样例#1:
    2
    

    说明

    【样例解释】

    如果道路1-4和1-5被破坏,含有节点(1,2,3,6,7,8)的子树将被分离出来 

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    #define N 151
    
    using namespace std;
    int n,m,ans,cnt,flag,w;
    int head[N],son[N],vis[N];
    struct node
    {
        int u,v,next; 
    }e[N<<1];
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    inline void add(int u,int v)
    {
        e[++cnt].v=v;e[cnt].next=head[u];head[u]=cnt;
    }
    
    void dfs2(int u,int tot)
    {
        if(son[u]==m)
        {
            w=tot;
            return;
        }
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].v;if(vis[i])continue;
            if(son[u]-son[v]>=m)
            {
                vis[i]=1;
                son[u]-=son[v];
                tot=tot+1;
                dfs2(u+1-1,tot);
                vis[i]=0;
            }
        }
    }
    
    void dfs(int u)
    {
        if(flag) return;
        for(int i=head[u];i;i=e[i].next)
        {
            dfs(e[i].v);
            if(son[u]<m) continue;
            else if(son[u]==m) 
            {
                printf("1
    ");
                flag=1;return;
            }
            else 
            {
                int tmp=son[u];
                dfs2(u,0);
                ans=min(ans,w);
                son[u]=tmp;
            }
        }
        if(flag) return;
    }
    
    void dfs1(int u)
    {
        son[u]=1;
        for(int i=head[u];i;i=e[i].next)
        {
            dfs1(e[i].v);
            son[u]+=son[e[i].v];
        }
    }
    
    int main()
    {
        int x,y;
        n=read();m=read();
        if(m==1)
        {
            printf("1
    ");
            return 0;
        }
        for(int i=1;i<n;i++)
        {
            x=read();y=read();
            add(x,y);
        }
        ans=0x3f3f3f3f;dfs1(1);
        dfs(1);
        if(!flag) printf("%d
    ",ans);
        return 0;
    }
    42分错误暴力
    /*
    显然树形dp
    dp[i][j]:i为根断掉子树大小为j最小边数
    初始化dp[u][1]=1的度数
    转移时枚举当前点断掉多少,算出连到的儿子断掉多少
    因为由儿子转移过来,他们之间的连边不能断
    但是转移时断掉了两次,所以答案减2 
    */
    
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    #define N 151
    #define inf 0x7f7f7f7f
    
    using namespace std;
    int dp[N][N],head[N],d[N];
    int n,m,ans,cnt;
    struct node
    {
        int u,v,next; 
    }e[N<<1];
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    inline void add(int u,int v)
    {
        e[++cnt].v=v;e[cnt].next=head[u];head[u]=cnt;
    }
    
    void dfs(int u,int fa)
    {
        dp[u][1]=d[u];
        for(int i=head[u];i;i=e[i].next)
        {
            if(e[i].v!=fa)
            {
                dfs(e[i].v,u);
                for(int j=m;j>=1;j--)
                  for(int k=1;k<=j;k++)
                    dp[u][j]=min(dp[u][j],dp[e[i].v][k]+dp[u][j-k]-2);
            }
        }ans=min(ans,dp[u][m]);
    }
    
    int main()
    {
        int x,y;
        memset(dp,1,sizeof dp);
        n=read();m=read();
        for(int i=1;i<n;i++)
        {
            x=read();y=read();
            add(x,y);add(y,x);
            d[x]++;d[y]++;
        }
        ans=inf;
        dfs(1,0);
        printf("%d
    ",ans);
        return 0;
    }
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    C语言截取从某位置开始指定长度子字符串方法
    vim:放弃hjkl
    vim资源
    PHP和.NET通用的加密解密函数类,均使用3DES加解密 .
    Java与.NET DES加密解密互转
    案例:使用正则表达式的爬虫
    爬虫的正则表达式re模块
    爬虫中Requests模块
    Oracle系列十一 数据处理
    爬虫urllib2 的异常错误处理URLError和HTTPError
  • 原文地址:https://www.cnblogs.com/L-Memory/p/7470215.html
Copyright © 2011-2022 走看看