zoukankan      html  css  js  c++  java
  • luogu P1272 重建道路

    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)的子树将被分离出来


     一开始想了各种神奇的东西,想着是不是要同时考虑上下两部分什么的,后来发现完全可以当成无根树嘛qwq

    ……↑以上请无视qwq

    树形DP一道。没有什么奇奇怪怪的输入真是太好了

    f[x][i]记录的是在以第x个点为根的子树上分出i个点的连通块最少需要删掉几条边

    初始化f[x][1]当然等于这个点的度数和

    dp转移方程f[x][j]=min(f[x][j],f[x][j-k]+f[v][k]-2)

    要减2的原因是转移过来的两个连通块之间那条边被删了两次,然而合并后的连通块中这条边不应该被删

    具体转移可以看代码qwq

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=200;
    int n,P,p[N],cnt,f[N][N],du[N];
    bool vis[N];
    struct edge{int to,nex;}e[N<<1];
    void add(int u,int v)
    {
        e[++cnt]=(edge){v,p[u]};
        p[u]=cnt;
    }
    void dfs(int x,int fa)
    {
        f[x][1]=du[x];
        for(int i=p[x];i;i=e[i].nex)
        {
            int v=e[i].to;
            if(v==fa)continue;
            dfs(v,x);
            for(int j=P;j>=1;--j)
            for(int k=1;k<=j;++k)
            f[x][j]=min(f[x][j],f[x][j-k]+f[v][k]-2);
        }
    }
    int main()
    {
        scanf("%d%d",&n,&P);
        memset(f,0x3f,sizeof(f));
        for(int i=1;i<n;++i)
        {
            int x,y;scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
            ++du[x],++du[y];
        }
        dfs(1,0);
        int ans=N;
        for(int i=1;i<=n;++i)ans=min(ans,f[i][P]);
        cout<<ans<<endl;
    } 
    road

    by:wypx


     树上dp,随便乱搞就过了,真好玩

    把我在luogu上的题解粘过来骗一波访问

    把一颗树以1(假装)为根节点,计算出他有多少个儿子,把他加一就是有多少连出去的边。

    重载dfs的w并没有什么用.....

    维护一个连通块(dp[i][1]就是把i这个节点删到只剩它自己需要操作多少次),然后大力扩展连通块,通过father节点加点,使其保持p个点在块里。

    然后枚举一遍在以没个i所扩展的大小为p的连通块所需要的操作次数

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    using namespace std;
    const int maxn=200;
    const int INT=2333333;
    int read(){
        int an=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while('0'<=ch&&ch<='9'){an=an*10+ch-'0';ch=getchar();}
        return an*f;
    }
    int f[maxn],cnt,fa[maxn],ans=2333;
    bool vis[maxn];
    struct saber{
    int to,nex;
    }b[maxn<<1];
    void add(int x,int y){
        cnt++;
        b[cnt].nex=f[x];
        b[cnt].to=y;
        f[x]=cnt;
    }
    int son[maxn],dp[maxn][maxn],m,n,p;
    void dfs(int x){
        vis[x]=1;son[x]=1;
        for(int i=f[x];i;i=b[i].nex){
            int v=b[i].to;
            if(!vis[v]){
                dfs(v);
                fa[v]=x;
                son[x]++;
            }
        }
    }
    void dfs(int x,int w){
        dp[x][1]=son[x];
        for(int i=f[x];i;i=b[i].nex){
            int v=b[i].to;
             if(v!=fa[x]){
             dfs(v,w);
            for(int j=p;j>=1;j--)
                for(int k=1;k<=j;k++)
                dp[x][j]=min(dp[x][j],dp[x][j-k]+dp[v][k]-2);
            }
        }
        ans=min(ans,dp[x][p]);
    }
    int main(){
        n=read();p=read();
        for(int i=0;i<=maxn-9;i++)
        for(int j=0;j<=maxn-9;j++)dp[i][j]=INT;
        for(int i=1;i<n;i++){
            int x,y;
            x=read();y=read();
            add(x,y);
            add(y,x);
        }
        dfs(1);son[1]--;
        dfs(1,INT);
        cout<<ans;
        return 0;
    } 
    1272

    by:s_a_b_e_r


  • 相关阅读:
    圆周率的计算与进度条
    Python的使用方法
    Python科学计算库
    linux 命令总结[转]
    如何在 Windows 平台上下載 Android 的源码[转]
    装MSN报错问题解决 无法定位程序输入点except handler4 common 于动态链接库nsvcrt.dll【转】
    编写xorg.conf,简单三行解决ubuntu分辩率不可调的问题【转】
    谁说 Android 手机一定要 root 权限才能截屏?![转]
    给自己的忠告[转]
    lockdir加密bug[转]
  • 原文地址:https://www.cnblogs.com/ck666/p/7625182.html
Copyright © 2011-2022 走看看