将军令(贪心&&树形DP)

Posted wwb123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将军令(贪心&&树形DP)相关的知识,希望对你有一定的参考价值。

只看45分的话,是树形DP....(当然也有能拿到70分+的大佬)

40分:

只考虑k==1的情况,树形DP

所以每个节点可能被父亲,自己,儿子控制

设f[MAXN][3],0表示儿子,1表示自己,2表示父亲

f[i][1]+=min(f[to][0],f[to][1],f[to][2])(因为自己控制自己,儿子怎样都行)

f[i][0]+=min(f[to][0],f[to][1])

但是因为i的儿子必须有一个自己控制自己,所以还要判断所加值中是否有f[to][1],如果没有

f[i][0]+=min(f[to][1]-f[to][0])

f[i][2]+=min(f[to][1],f[to][0])

技术图片
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<map>
 6 #include<vector>
 7 #include<set>
 8 #include<cmath>
 9 #define MAXN 600001
10 #define int long long
11 using namespace std;
12 struct nodeint to,n;e[MAXN*2];
13 int head[MAXN],tot;
14 void add(int u,int v)
15 
16      e[++tot].to=v;e[tot].n=head[u];head[u]=tot;
17 
18 int read()
19 
20     int x=0;char c=getchar();
21     while(c<0||c>9)c=getchar();
22     while(c>=0&&c<=9)
23     
24         x=(x<<1)+(x<<3)+(c^48);
25         c=getchar();
26     
27     return x;
28 
29 int f[MAXN][4];//0 儿子 1 自己 2 父亲
30 void DFS(int x,int fa)
31 
32     int ok=1,minn=100000;
33     f[x][1]=1;
34     for(int i=head[x];i;i=e[i].n)
35     
36         int to=e[i].to;
37         if(to==fa)continue;
38         DFS(to,x);
39         if(f[to][1]<=f[to][0])
40         
41            f[x][0]+=f[to][1];
42            ok=0;
43         
44         else f[x][0]+=f[to][0];
45         f[x][1]+=min(f[to][1],min(f[to][2],f[to][0]));
46         f[x][2]+=min(f[to][1],f[to][0]);
47     
48     if(ok==1)
49     
50        for(int i=head[x];i;i=e[i].n)
51        
52            int to=e[i].to;
53            if(to==fa)continue;
54            minn=min(minn,f[to][1]-f[to][0]);
55        
56        f[x][0]+=minn;
57         
58 
59 int n,k,t;
60 signed main()
61 
62     n=read();k=read();t=read();
63     for(int i=1;i<=n-1;++i)
64     
65         int x,y;
66         x=read();y=read();
67         add(x,y);add(y,x);
68     
69     if(k==0)
70     
71        printf("%lld\n",n);
72        return 0;
73     
74     DFS(1,0);
75     printf("%lld\n",min(f[1][1],f[1][0]));
76 
45分

100分

贪心很好想吧.....

每次选出深度最大的节点,找到他的第k级祖先,然后暴力修改他的k距离范围内的点

正确性的话,我们每次恰好选k级祖先(或根),对于覆盖范围来说,肯定比k级祖先的父亲和儿子要好啦啦.....

技术图片
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<map>
 6 #include<vector>
 7 #include<set>
 8 #include<algorithm>
 9 #include<cmath>
10 #include<queue>
11 #define MAXN 1000001
12 using namespace std;
13 struct nodeint to,n;e[MAXN*2];
14 int n,k,t;
15 int head[MAXN],tot=0;
16 int read()
17 
18      char c=getchar();int x=0;
19      while(c<0||c>9)c=getchar();
20      while(c>=0&&c<=9)
21      
22           x=(x<<1)+(x<<3)+(c^48);
23           c=getchar();
24       
25      return x;
26 
27 void add(int u,int v)
28 
29      e[++tot].to=v;e[tot].n=head[u];head[u]=tot;
30 
31 priority_queue<pair<int,int> >q;
32 int fa[MAXN];
33 int deep[MAXN];
34 void DFS(int x,int faa)
35         
36      q.push(make_pair(deep[x],x));
37      for(int i=head[x];i;i=e[i].n)
38      
39          int to=e[i].to;
40          if(faa==to)continue;
41          fa[to]=x;
42          deep[to]=deep[x]+1;
43          DFS(to,x);
44      
45 
46 bool vis[MAXN];
47 int find(int x,int kk)
48 
49     if(deep[x]<=kk)return 1;
50     while(kk!=0)
51     
52         kk--;
53         x=fa[x];  
54     
55     return x;
56 
57 void check(int x,int faa,int root,int kx)
58 
59      if(kx>k)return ;
60      vis[x]=1;
61      //printf("vis[%d]=%d deep[%d]=%d\n",x,vis[x],root,deep[root]);
62      for(int i=head[x];i;i=e[i].n)
63      
64          int to=e[i].to;
65          if(to==faa)continue;
66          check(to,x,root,kx+1);
67      
68      return ;
69 
70 int ans=0;
71 void work()
72 
73     while(!q.empty())
74     
75         int top=q.top().second;
76         //printf("top=%d\n",top);
77         q.pop();
78         if(vis[top]==1)continue;
79         int faa=find(top,k);
80         //printf("faa=%d\n",faa);
81         check(faa,0,faa,0);
82         ans++;
83     
84 
85 signed main()
86 
87     n=read();k=read();t=read();
88     for(int i=1;i<=n-1;++i)
89     
90         int x,y;
91         x=read();y=read();
92         add(x,y);add(y,x);
93     
94     deep[1]=1;
95     DFS(1,0);
96     work();
97     printf("%d\n",ans);
98 
View Code

还有要注意的一点,在找与祖先相邻为k的点时暴力查找,不看深度。。。。

 

以上是关于将军令(贪心&&树形DP)的主要内容,如果未能解决你的问题,请参考以下文章

求树的最大独立集,最小点覆盖,最小支配集 贪心and树形dp

noip模拟赛 将军令

2021陕西省赛 D.Disease(树形dp&期望dp)

2021陕西省赛 D.Disease(树形dp&期望dp)

P2279 消防局的设立 (树形DP or 贪心)

LuoguP4719 模板动态 DP(树形DP,矩阵加速,LCT)