• [ CodeVS冲杯之路 ] P1091


      不充钱,你怎么AC?

      题目:http://codevs.cn/problem/1091/

      大家都写的 DFS,然而我想到了一种贪心的做法,重点是可以A

      普遍的贪心是每次删掉该深度子树最大的点,但是如果有一边卡一条链就会WA

      我们何不进一步考虑贪心,如果它下面是一条链我们就可以缓一缓到第 2 天再删是不是,反正它每次也就增加一个人

      用 size[x] 记录所有后代加上自己的节点个数,f[x] 记录其最大子树的 size 值

      我们考虑第一次不删这个节点,让它先扩展一次,然后第二次再删除它子树中 size 最大的节点

      那么设 g[x]=size[x]-f[x],g 就为第一次不删,第二次删掉其最大的子树还剩余的节点数

      一条链的 g[x]=1,而一个多叉节点的 g[x]>1,这就意味着先要删去 g 值更大的那个节点,才能不让它下一次扩展更多的出来

      那么一层层地贪心,每次删掉 g 值最大的节点,直到不再继续传染为止

      贪心跑得飞快~

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<cmath>
     7 #include<stack>
     8 using namespace std;
     9 
    10 const int N=301;
    11 stack<int> s,q;
    12 int first[N],v[N*2],next[N*2],size[N],g[N],f[N];
    13 void dfs(int x,int fa)
    14 {
    15     f[x]=fa;
    16     int i;
    17     for (i=first[x];i;i=next[i])
    18         {
    19             if (v[i]==fa) continue;
    20             dfs(v[i],x);
    21             if (size[v[i]]>g[x]) g[x]=size[v[i]];
    22         }
    23     size[fa]+=size[x];
    24 }
    25 int main()
    26 {
    27     int n,m,i,x,ans=0;
    28     scanf("%d%d",&n,&m);
    29     for (i=1;i<=m;i++)
    30         {
    31             scanf("%d%d",&x,&v[i]);
    32             v[i+m]=x;
    33             next[i]=first[x];
    34             first[x]=i;
    35             next[i+m]=first[v[i]];
    36             first[v[i]]=i+m;
    37         }
    38     for (i=1;i<=n;i++) size[i]=1;
    39     dfs(1,0);
    40     for (i=1;i<=n;i++) g[i]=size[i]-g[i];
    41     s.push(1);
    42     g[0]=size[0]=0;
    43     ans=n;
    44     while (!s.empty())
    45         {
    46             m=0;
    47             while (!s.empty())
    48                 {
    49                     x=s.top();
    50                     s.pop();
    51                     for (i=first[x];i;i=next[i])
    52                         {
    53                             if (v[i]==f[x]) continue;
    54                             if (g[v[i]]>g[m]||(g[v[i]]==g[m]&&size[v[i]]>size[m])) m=v[i];
    55                             q.push(v[i]);
    56                         }
    57                 }
    58             while (!q.empty())
    59                 {
    60                     x=q.top();
    61                     q.pop();
    62                     if (x==m) ans-=size[m];
    63                     else s.push(x);
    64                 }
    65         }
    66     printf("%d
    ",ans);
    67     return 0;
    68 }

      这里有个DFS的:http://blog.csdn.net/yuyanggo/article/details/48087431

      贪心的做法证明有人会严谨的吗?会的话告诉我谢谢!

  • 相关阅读:
    HDU 5265 pog loves szh II (二分查找)
    不删除记录的表CRUD的常见处置
    如果真的不知道将来要做什么
    爪哇国新游记之三十三----目录文件操作
    一个类似股票看板的自刷新页面的制作
    转载:什么才是程序员的核心竞争力
    又见The request sent by the client was syntactically incorrect ()
    uefi版和装机版有什么区别?
    Mealy和moore型状态机的主要区别
    FIFO、UART、ALE解释
  • 原文地址:https://www.cnblogs.com/hadilo/p/5916654.html
Copyright © 2020-2023  润新知