[ 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\n",ans);
67     return 0;
68 }

 

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

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

posted @ 2016-09-28 15:46  Hadilo  阅读(286)  评论(4编辑  收藏  举报