• 牛客nc22598 Rinne Loves Edges


    题目链接:https://ac.nowcoder.com/acm/problem/22598

    简单题意:给定一棵有边权的树和一个点S,删去一些边使得所有的叶子和S不连通。求删去的最小边权和

    可以把S看做根。f[i]表示使得i的子树上的叶子和i不连通,删去的最小边权和。则有f[i]=Σmin(f[j],dis[i][j]),其中j是i的子结点。这题的n<=1e6,不能直接用dis数组存边权,可以用邻接表顺便存下来。最后答案就是f[s]

    #include<bits/stdc++.h>
    #define ll long long
    #define pb push_back
    using namespace std;
    
    const int maxn=1e5+10;
    struct st{int ver,w;}; 
    vector<st> g[maxn];
    int t,n,m,s,i,j,k,vis[maxn];
    ll f[maxn];
    
    void dp(int u){
    	vis[u]=1; int num=0; 
    	for (int i=0;i<g[u].size();i++) //判断叶子 
    	  if (vis[g[u][i].ver]==0) num++;
    	if (num==0) f[u]=1e10;
    	for (int i=0;i<g[u].size();i++){
    	  int k=g[u][i].ver; //子节点 
    	  if (vis[k]) continue;
    	  dp(k);
    	  if (f[k]>g[u][i].w) f[u]+=g[u][i].w;else f[u]+=f[k]; 
    	}
    }
    
    int main(){
    	scanf("%d%d%d",&n,&m,&s);
    	for (i=1;i<n;i++){
    	  int x,y,w; st e;
    	  scanf("%d%d%d",&x,&y,&w); e.w=w;
    	  e.ver=x; g[y].pb(e);
    	  e.ver=y; g[x].pb(e);
    	}
    	dp(s);
    	printf("%lld
    ",f[s]);
    	return 0;
    }
    

      

    一道类似的题:牛客nc210473

    题目链接:https://ac.nowcoder.com/acm/problem/210473

    简单题意:删去一些边,使得叶子和根节点1不连通。求删去的边权和<=m的情况下,其中最大边权的最小值

    要求最小的最大值,考虑二分答案mid,然后用上一题的树形dp来判断最大值为mid的情况下,结果f[1]和m的关系即可。注意做树形dp的时候如果边权>mid就不能删掉这个边,只能删掉子树

    #include<bits/stdc++.h>
    #define pb push_back
    using namespace std;
     
    vector<int> g[1010];
    int n,m,i,l,r,mid,d[1010][1010],vis[1010],f[1010];
     
    void dp(int u){
        vis[u]=1; int num=0;
        for (int i=0;i<g[u].size();i++)
          if (!vis[g[u][i]]) num++;
        if (num==0) f[u]=1e6;
        for (int i=0;i<g[u].size();i++){
          int k=g[u][i];
          if (vis[k]) continue;
          dp(k);
          if (d[u][k]>mid) f[u]+=f[k]; else f[u]+=min(f[k],d[u][k]);
        }
    }
     
    int main(){
        cin>>n>>m;
        for (i=1;i<n;i++){
          int x,y,dis;
          cin>>x>>y>>dis;
          g[x].pb(y);g[y].pb(x);
          d[x][y]=d[y][x]=dis;
        }
        l=0;r=1e3+10;
        while (l<r-1){
          memset(vis,0,sizeof(vis)); memset(f,0,sizeof(f));
          mid=(l+r)/2; dp(1);
          if (f[1]>m) l=mid; else r=mid;
        }
        if (r==1e3+10) cout<<-1<<endl; else cout<<r<<endl;
        return 0;
    }
    

      

  • 相关阅读:
    ObjectiveC初步研究 实现文件(Implementation File)
    SQL技巧(二) CTE(公用表达式)初步接触
    ObjectiveC编程基础
    Linux编程 使用C在mysql中插入数据
    办理户口
    修改kernel内核HZ频率没有效果问题
    如何从湖北省人才市场将户口迁移出来?
    查看 各种寄存器值的 内核模块 C语言
    SDRAM AND SRAM
    linux2.6.26内核中ARM中断实现详解(转)
  • 原文地址:https://www.cnblogs.com/edmunds/p/13497758.html
Copyright © 2020-2023  润新知