将军令(贪心&&树形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 node{int 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 node{int 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 }

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

原文地址:https://www.cnblogs.com/Wwb123/p/11336045.html

时间: 2024-08-27 13:52:36

将军令(贪心&&树形DP)的相关文章

bzoj 1907: 树的路径覆盖【贪心+树形dp】

我是在在做网络流最小路径覆盖的时候找到这道题的 然后发现是个贪心+树形dp \( f[i] \)表示在\( i \)为根的子树中最少有几条链,\( v[i] \) 表示在\( i \)为根的子树中\( i \) 是( 0)否(1)为一条链的端点 然后贪心转移即可(有链端点则连起来) #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=10005; i

BZOJ 4027:[HEOI2015]兔子与樱花(贪心+树形DP)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4027 [题目大意] 樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1个树枝连接, 我们可以把它看成一个有根树结构,其中0号节点是根节点. 这个树的每个节点上都会有一些樱花,其中第i个节点有c_i朵樱花. 樱花树的每一个节点都有最大的载重m,对于每一个节点i, 它的儿子节点的个数和i节点上樱花个数之和不能超过m,即son(i)+c_i<=m, 其中son(i)表示i的

hdu4313 贪心并查集 || 树形dp

http://acm.hdu.edu.cn/showproblem.php?pid=4313 Problem Description Machines have once again attacked the kingdom of Xions. The kingdom of Xions has N cities and N-1 bidirectional roads. The road network is such that there is a unique path between any

Codeforces 77C 树形dp + 贪心

题目链接:点击打开链接 题意: 给定n个点, 每个点的豆子数量 下面是一棵树 再给出起点 每走到一个点,就会把那个点的豆子吃掉一颗. 问:回到起点最多能吃掉多少颗豆子 思路:树形dp 对于当前节点u,先把子节点v都走一次. 然后再往返于(u,v) 之间,直到u点没有豆子或者v点没有豆子. dp[u] 表示u点的最大值.a[u] 是u点剩下的豆子数. #include <cstdio> #include <vector> #include <algorithm> #inc

POJ 2057 The Lost House 经典树形DP+贪心

题意:链接 方法:树形DP+贪心 解析:这是一道好题. 好首先要明确这题求的是什么? 名义上是期望值,而实际上就是找一条路径.什么路径呢?从根节点走遍所有的叶子节点所花费步数最短的路径. 明确了题意后该怎么做呢? 首先看我们需要什么? 目前有个根节点,我们需要知道从他向一个分支走,失败步数是多少,成功步数是多少? 那么怎么维护我们需要的东西呢? 首先我们先给他们起个名:suc,fai; 其次再给一个节点的叶子节点的个数起个名:son 起名完事之后我们就要更新了. 先谈叶子节点,显然叶子节点的su

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

(点击此处查看原题) 树形DP写法 看到这个题的要求,很容易相到这是一个树形DP的问题,但是dp数组应该如何设计并转移才是关键 dp[i][0]代表当前结点可以向上覆盖2层,自身一定被覆盖dp[i][1]代表当前结点可以向上覆盖1层,自身一定被覆盖dp[i][2]代表当前结点可以向上覆盖0层,自身一定被覆盖dp[i][3]代表当前结点可以向下覆盖1层,表示自己不一定被覆盖,但是儿子一定全部被覆盖dp[i][4]代表当前结点可以向下覆盖2层,表示自己不一定被覆盖,但是孙子一定全部被覆盖 所谓向上覆

一道树形DP+贪心题——FramCraft

题目大意: mhy住在一棵有n个点的树的1号结点上,每个结点上都有一个妹子. mhy从自己家出发,去给每一个妹子都送一台电脑,每个妹子拿到电脑后就会开始安装zhx牌杀毒软件,第i个妹子安装时间为. 树上的每条边mhy能且仅能走两次,每次耗费1单位时间.mhy送完所有电脑后会回自己家里然后开始装zhx牌杀毒软件. 卸货和装电脑是不需要时间的. 求所有妹子和mhy都装好zhx牌杀毒软件的最短时间. 分析一下题意: 树上的每条边mhy能且仅能走两次,这个有什么用? 很有用.自己想想!我不说了,模拟模拟

【bzoj1907】树的路径覆盖 树形dp

题目描述 输入 输出 样例输入 1 7 1 2 2 3 2 4 4 6 5 6 6 7 样例输出 3 题解 树形dp 设f[x]表示以x为根的子树完成路径覆盖,且x为某条路径的一端(可以向上延伸)的最小路径数,g[x]表示以x为根的子树完成路径覆盖,且x不为某条路径的一端的最小路径数. 那么考虑点x,只有三种情况:单独成路径.与一条子树的链成路径.与两条子树的链成路径. 这三种情况分别对应三种状态转移方程,具体见代码. 然而看到网上题解大把大把的贪心我也是醉了qaq #include <cstd

树形DP 树的最小支配集,最小点覆盖与最大独立集

最小支配集: 从V中选取尽量少的点组成一个集合,让V中剩余的点都与取出来的点有边相连. (点) 最小点覆盖: 从V中选取尽量少的点组成一个集合V1,让所有边(u,v)中要么u属于V1,要么v属于V1 (边) 最大独立集: 从V中选取尽量多的点组成一个集合,让这些点中间没有边项链,也就是说对于任何一条边,u,v不能同时属于集合V1. 1.贪心算法 首先选取一个点为根节点,求出所有节点对应的DFS序列,按照所得序列反向进行贪心,这样保证对于每个点来说,当子树都被处理过之后才会处理该节点 int p[