uvalive3902(树上的最优化 贪心)

题目链接:https://vjudge.net/problem/UVALive-3902

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #include<algorithm>
 5 using namespace std;
 6
 7 const int maxn=1010;
 8 vector<int> gr[maxn],nodes[maxn];
 9 int n,s,k,fa[maxn];
10 bool covered[maxn];
11 void dfs(int u,int f,int d)
12 {
13     fa[u]=f;  //计算fa数组
14     int nc=gr[u].size();
15     if(nc==1&&d>k) nodes[d].push_back(u);   //根据深度把叶子结点插入nodes里
16     for(int i=0;i<nc;i++)
17     {
18         int v=gr[u][i];
19         if(v!=f) dfs(v,u,d+1);
20     }
21 }
22
23 void dfs2(int u,int f,int d)
24 {
25     covered[u]=1;
26     int nc=gr[u].size();
27     for(int i=0;i<nc;i++)
28     {
29         int v=gr[u][i];
30         if(v!=f&&d<k) dfs2(v,u,d+1); //覆盖到新服务器距离不差过k的点
31     }
32 }
33
34 int solve()
35 {
36     int ans=0;
37     memset(covered,0,sizeof(covered));
38     for(int d=n-1;d>k;d--)
39         for(int i=0;i<nodes[d].size();i++)
40     {
41         int u=nodes[d][i];
42         if(covered[u]) continue; //已经覆盖的不考虑
43         int v=u;
44         for(int j=0;j<k;j++) v=fa[v];  //v是u的k级祖先
45         dfs2(v,-1,0);  //在节点v放置服务器
46         ans++;
47     }
48     return ans;
49 }
50 int main()
51 {
52     int t;
53     scanf("%d",&t);
54     while(t--)
55     {
56         scanf("%d%d%d",&n,&s,&k);
57         for(int i=0;i<=n;i++)
58         {
59             gr[i].clear();
60             nodes[i].clear();
61         }
62         for(int i=0;i<n-1;i++)
63         {
64             int a,b;
65             scanf("%d%d",&a,&b);
66             gr[a].push_back(b);
67             gr[b].push_back(a);
68         }
69         dfs(s,-1,0);
70         printf("%d\n",solve());
71     }
72     return 0;
73 }
时间: 2024-10-16 13:08:17

uvalive3902(树上的最优化 贪心)的相关文章

Vijos[1983]NOIP2015Day2T3 运输计划 transport LCA

题目链接Vijos 题目链接UOJ 转载一个大佬的题解: 点击这里->银牌爷题解 主要考察二分查找.树上倍增.贪心."树上前缀和".题目是一颗树,要求将一条边的权值变为0,使得所有运输计划的最大时间最小.直觉告诉我们,这是一个树上倍增的题目,但是它却不像前几年的 Day2T3 开车旅行那样纯倍增,或许更像疫情控制一些,倍增只是辅助算法,还需要配合其他算法.由于要使所有运输计划的最大时间最小,不难想到二分答案的方法.使C(t)表示是否可以改造一条边,使得改造之后所有运输计划中最长的

Codeforces 706D Vasiliy&#39;s Multiset(可持久化字典树)

[题目链接] http://codeforces.com/problemset/problem/706/D [题目大意] 要求实现一个集合中的三个操作,1:在集合中加入一个元素x,2:从集合中删除一个元素x(保证x存在),3:要求从集合中选出一个数,使得其与给出的数x的异或值最大,输出这个异或值. [题解] 可以将所有的以二进制形式存在01字典树上,删除即插入权值为-1的二进制串,对于异或值最大的操作,我们只要在字典树上按位贪心,从最高位开始尽量保证该位存在最后就能得到答案.写代码的时候直接写了

AHOI2018 排列

首先是那个非常吃shi的题意,想好久一会就能发现题里面的意思是: 如果某一个数的值为x,那么它必须排在第x个数后面. 然后我们就可以发现形成了一棵树,第i个数的父亲是i,如果出现了环就说明无解. 于是原题变成了:给出一棵n+1个节点以0为根的树,选每个数之前必须选他的父亲,第i个数将会对答案造成w×i的贡献,最大化收益. 显然每次取出权值最小的点会更优,若某个点是当前最小的,那么取出当前点父亲之后,必然会立刻取出当前点. 于是我们可以将这两个点合并. 稍微推一下式子,新的点更优的条件是平均数更小

【POJ3659】【USACO 2008 Jan Gold】 3.Cell Phone Network 树上最小支配集/贪心 两种做法

题意:求树上最小支配集 最小支配集:点集,即每个点可以"支配"到相邻点,求最少点数可以使所有点被支配. 图上的最小支配集是NP的,但是树上的可以DP做,是O(n)的. 暴力做就好了, f[i]表示此 点被选时的子树全支配的最小代价 g[i]表示其父亲节 点被选时的子树全支配的最小代价 h[i]表示其某子节 点被选时的子树全支配的最小代价 然后暴力转移. (v是子节点) f[x]=∑(min(f[v],min(g[v],h[v])))+1; g[x]=∑(min(f[v],h[v]));

bzoj 2525: [Poi2011]Dynamite【二分+树上贪心】

一眼二分.然后重点是树上贪心部分 长得像dp一样,设mn为子树内已炸点的最浅点,mx为子树内没有炸并且需要炸的最深点,然后转移直接从子树继承即可 然后是判断当前u点是否需要炸,当mx[u]+mn[u]<=mid,当前子树可以自己消化,所以mx[u]=-inf:否则,就需要在u炸一下 #include<iostream> #include<cstdio> using namespace std; const int N=300005; int n,m,h[N],cnt,d[N]

HDU5242 Game(树上贪心)

题目链接 Game 题目的意思很简单, 就是要找一棵树权值最大等等前K条链. 在本题中,走的次数等于min(叶子结点个数,k) tree[i].sum意为从i号结点出发走到某个叶子结点能得到的最大总价值. pson[i]表示i号结点若要获得最大价值那么下一步该怎么走. 显然tree[i].sum和pson[i]是从i的各个儿子转移得到的. 那么先做一遍DFS计算出tree[i].sum, 再排序. 然后贪心,从价值最大的那个结点开始选,从大到小. 选的时候,要把他中途经过的结点全部屏蔽(就是说被

【CF700B】Connecting Universities(想法题,贪心,树上最短路)

题意:给出一棵树上的2*k个节点,给他们配对,使得他们之间的距离和最大. 思路:一条边的两侧如果有一侧没有给定的节点就不会被经过…… 如果有1个节点就会被经过1次…… 如果两侧分别有x,y个给定节点就会被经过min(x,y)次 因为要使总路程最大就是让每一条路被走过最多的次数 肯定是两侧各取一个 剩下的只能在某侧内部解决 所以按此统计即可 答案很大 用INT64 1 var head,vet,next,a,b,c,dep,flag,f:array[1..500000]of longint; 2

UVALive3902 Network[贪心 DFS&amp;&amp;BFS]

UVALive - 3902 Network Consider a tree network with n nodes where the internal nodes correspond to servers and the terminal nodes correspond to clients. The nodes are numbered from 1 to n. Among the servers, there is an original server S which provid

Codeforces Round #480 (Div. 2) C 贪心 D 数字、思维 E 树上倍增

Codeforces Round #480 (Div. 2) C. Posterized 题意: 给出 n 个数,都是区间 [0,255] 内的数,要你把 [0,255] 划分成多个长度 <=k 的不重叠的子区间.每个数必须包含在一个子区间内,且这个数的价值是这个子区间的左端点.要你输出这 n 数的价值,且这 n 个价值字典序要最小. tags: 首先很明显字典序最小,那对于第 i 个数 p[i] 定它的区间时,左端点肯定要尽可能小.所以我们直接枚举区间 [ p[i]-k+1, p[i] ] 定