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

    题目:

    Description

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

    Input

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

    Output

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


    树形DP 用了两种方式)

    一:边集数组

    1. f[x][p]表示以x为根的子树保留p个点要删除的最小边数
    2. 状态转移方程:f[x][j]=min(f[x][j],f[t[i].v][k]+f[x][j-k]-2)
    3. 转移时枚举当前点删除多少边,儿子节点能删除多少条边
    4. 因为由儿子转移过来,他们之间的连边不能断,but转移时断掉了两次,所以ans-2

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    const int N=305,M=100000000;
    int n,p,a[N],d[N],f[N][N],tot,ans;
     struct ss
    {
        int nx,v;
    }t[N*2];
     void add(int u,int v)//边集数组
    {
        tot++; t[tot].v=v; t[tot].nx=a[u]; a[u]=tot;
    }
     void dp(int x,int fa)//x为当前节点,fa为当前节点的父节点
    {
        f[x][1]=d[x]; //x节点保留1个节点时将与x节点相连的子节点断开 
        int i,j,k;
        for (k=a[x]; k; k=t[k].nx)  
            if (t[k].v!=fa)
            {
                dp(t[k].v,x);
                for (i=p; i>=1; i--)
                    for (j=1; j<=i; j++) f[x][i]=min(f[x][i],f[t[k].v][j]+f[x][i-j]-2);
            }
        ans=min(ans,f[x][p]);
    }
     int main()
    {
        memset(f,0x03f,sizeof(f));
        scanf("%d%d",&n,&p);
        int x,y;
        for (int i=1; i<n; i++)
        {
            scanf("%d%d",&x,&y);
            d[x]++; d[y]++;
            add(x,y); add(y,x);
        }
        ans=M;
        dp(1,0);
        printf("%d\n",ans);
        return 0;
    }

    二:f[x][p]表示以x为根的子树保留p个点要删除的最小边数

    • res[rx][p]表示x节点右边最近的节点保留p个点要删除的最小边数
    • 上一种方式相比,多用res数组记录兄弟节点的值,而上一种则是从p至1循环防止前面更新的值对后面的值产生影响
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    const int N=305,M=1000000000;
    int a[N],nx[N],f[N][N],res[N][N];
    int n,p,root,ans=M;
    bool flag[N];
     void dfs(int x)
    {
        for (int i=0; i<=p; i++) f[x][i]=res[x][i]=M;
        f[x][0]=1;
        if (a[x]==0)
        {
            f[x][1]=0;
            return;
        }
        int i,j,k,rk=0;
        for (k=a[x]; k; k=nx[k])
        {
            dfs(k);
            if (rk>0)
                for (i=0; i<=p; i++)
                    for (j=0; j<=i; j++) 
                        res[k][i]=min(res[k][i],res[rk][j]+f[k][i-j]);
            else for (i=0; i<=p; i++) res[k][i]=f[k][i];
            rk=k;
        }
        for (i=1; i<=p; i++) f[x][i]=res[rk][i-1];
    }
     int main()
    {
        scanf("%d%d",&n,&p);
        int u,v;
        for (int i=1; i<n; i++) 
        {
            scanf("%d%d",&u,&v);
            nx[v]=a[u]; a[u]=v;
            flag[v]=true;
        }
        for (int i=1; i<=n; i++)
            if (flag[i]==false) {root=i; break;}
        dfs(root);
        for (int i=1; i<=n; i++)
            if (i==root) ans=min(ans,f[i][p]);
            else ans=min(ans,f[i][p]+1);
        printf("%d\n",ans);
        return 0;
    }
  • 相关阅读:
    linux-vi/vim
    Linux性能监控-ss
    Linux性能监控-netstat
    Linux性能监控-sar
    Linux性能监控-htop
    Linux性能监控-pstree
    Linux性能监控-ps
    查看linux占用内存/CPU最多的进程
    Linux性能监控-top
    Linux-cpu-socket/core/processor
  • 原文地址:https://www.cnblogs.com/lyxzhz/p/11403938.html
Copyright © 2011-2022 走看看