题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6178

题意:给出一棵有n个节点的树,现在需要你把k只猴子放在节点上,每个节点最多放一只猴子,且要求每只猴子必有一只另外的猴子通过一条边与它相连,问最少用多少条边能达到这个要求。

解法:利用贪心的思维,显然我们应该先选择性价比最高的,即一条边连接两个点的情况。计算出这样的边的条数ans,如果ans*2>=k,结果就是(k+1)/2,否则剩下来没有安排的猴子每一只需要多一条边,即结果为ans+k-2 * ans。我的方法是用类拓扑排序的方法,找连接两个度数为1且没用被用过的点的边数,每次找到一条边后注意更新度数。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
struct FastIO
{
static const int S = 1310720;
int wpos;
char wbuf[S];
FastIO() : wpos(0) {}
inline int xchar()
{
static char buf[S];
static int len = 0, pos = 0;
if(pos == len)
pos = 0, len = fread(buf, 1, S, stdin);
if(pos == len)
exit(0);
return buf[pos ++];
}
inline unsigned long long xuint()
{
int c = xchar();
unsigned long long x = 0;
while(c <= 32)
c = xchar();
for(; '0' <= c && c <= '9'; c = xchar())
x = x * 10 + c - '0';
return x;
}
inline long long xint()
{
long long s = 1;
int c = xchar(), x = 0;
while(c <= 32)
c = xchar();
if(c == '-')
s = -1, c = xchar();
for(; '0' <= c && c <= '9'; c = xchar())
x = x * 10 + c - '0';
return x * s;
}
inline void xstring(char *s)
{
int c = xchar();
while(c <= 32)
c = xchar();
for(; c > 32; c = xchar())
* s++ = c;
*s = 0;
}
inline double xdouble()
{
bool sign = 0;
char ch = xchar();
double x = 0;
while(ch <= 32)
ch = xchar();
if(ch == '-')
sign = 1, ch = xchar();
for(; '0' <= ch && ch <= '9'; ch = xchar())
x = x * 10 + ch - '0';
if(ch == '.')
{
double tmp = 1;
ch = xchar();
for(; ch >= '0' && ch <= '9'; ch = xchar())
tmp /= 10.0, x += tmp * (ch - '0');
}
if(sign)
x = -x;
return x;
}
inline void wchar(int x)
{
if(wpos == S)
fwrite(wbuf, 1, S, stdout), wpos = 0;
wbuf[wpos ++] = x;
}
inline void wint(long long x)
{
if(x < 0)
wchar('-'), x = -x;
char s[24];
int n = 0;
while(x || !n)
s[n ++] = '0' + x % 10, x /= 10;
while(n--)
wchar(s[n]);
}
inline void wstring(const char *s)
{
while(*s)
wchar(*s++);
}
inline void wdouble(double x, int y = 6)
{
static long long mul[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000LL, 100000000000LL, 1000000000000LL, 10000000000000LL, 100000000000000LL, 1000000000000000LL, 10000000000000000LL, 100000000000000000LL};
if(x < -1e-12)
wchar('-'), x = -x;
x *= mul[y];
long long x1 = (long long) floorl(x);
if(x - floor(x) >= 0.5)
++x1;
long long x2 = x1 / mul[y], x3 = x1 - x2 * mul[y];
wint(x2);
if(y > 0)
{
wchar('.');
for(size_t i = 1; i < y && x3 * mul[i] < mul[y]; wchar('0'), ++i);
wint(x3);
}
}
~FastIO()
{
if(wpos)
fwrite(wbuf, 1, wpos, stdout), wpos = 0;
}
} io;
const int maxn = 100010;
struct edge{
int to,next;
}E[maxn*2];
int head[maxn],edgecnt;
void init(){
edgecnt=0;
memset(head,-1,sizeof(head));
}
void add(int u, int v){
E[edgecnt].to=v,E[edgecnt].next=head[u],head[u]=edgecnt++;
}
int du[maxn];
bool vis[maxn]; int main()
{
int T,n,k;
T = io.xuint();
while(T--)
{
init();
memset(vis,0,sizeof(vis));
n = io.xuint();
k = io.xuint();
for(int i=2; i<=n; i++){
int x;
x = io.xuint();
add(i, x);
add(x, i);
du[x]++;
du[i]++;
}
queue<int>q;
for(int i=1; i<=n; i++){
if(du[i] == 1){
q.push(i);
}
}
int ans = 0;
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i=head[u]; i+1; i=E[i].next){
int v = E[i].to;
if(!vis[u]&&!vis[v]){
vis[u]=1;
vis[v]=1;
ans++;
}
du[v]--;
if(du[v]==1){
q.push(v);
}
}
}
if(ans*2>=k){
printf("%d\n", (k+1)/2);
}
else{
ans = ans+k-2*ans;
printf("%d\n", ans);
}
}
return 0;
}

我还在网上看到了另外一种利用树形DP解决这个题的方法,觉得挺妙的,他的方法是这样的。http://blog.csdn.net/my_sunshine26/article/details/77586785

我们尽量要使一个点只匹配一个点,很容易想到二分匹配中的最大匹配数,而最大匹配数即为最小点覆盖数,可用树形DP解决。

我们用dp[i][1]表示选择i这个顶点(初始化dp[root][1]为1)的最小点覆盖数,那么它的儿子节点son[i]可以被选择也可以不被选择。

状态转移方程为 dp[i][1]+=min(dp[son[i]][0],dp[son[i]][1]);

用dp[i][0]表示不选择i这个顶点(初始化dp[root][0]为0)的最小点覆盖数,显然它的儿子节点son[i]就必须被选择了。

状态转移方程为 dp[i][0]+=dp[son[i]][1];

最终求出最小点覆盖数(最大匹配数)即为min(dp[1][0],dp[1][1]),也就求出了ans,然后跟上面的步骤相同。

2017多校第10场 HDU 6178 Monkeys 贪心,或者DP的更多相关文章

  1. 2017多校第10场 HDU 6180 Schedule 贪心,multiset

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6180 题意:给了一些任务的开始时间和终止时间,现在让我们安排k台及机器,让这些任务在k太机器上最小,并 ...

  2. 2017多校第10场 HDU 6171 Admiral 双向BFS或者A*搜索

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6171 题意: 给你一个高度为6的塔形数组,你每次只能将0与他上下相邻的某个数交换,问最少交换多少次可以 ...

  3. 2017多校第10场 HDU 6181 Two Paths 次短路

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6181 题意:给一个图,求出次短路. 解法:我之前的模板不能解决这种图,就是最短路和次短路相等的情况,证 ...

  4. 2017多校第10场 HDU 6172 Array Challenge 猜公式,矩阵幂

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6172 题意:如题. 解法: #include <bits/stdc++.h> using ...

  5. 2017多校第9场 HDU 6161 Big binary tree 思维,类似字典树

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6161 题意: 题目是给一棵完全二叉树,从上到下从左到右给每个节点标号,每个点有权值,初始权值为其标号, ...

  6. 2017多校第9场 HDU 6169 Senior PanⅡ 数论,DP,爆搜

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6169 题意:给了区间L,R,求[L,R]区间所有满足其最小质数因子为k的数的和. 解法: 我看了这篇b ...

  7. 2017多校第8场 HDU 6138 Fleet of the Eternal Throne AC自动机或者KMP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6138 题意:给n个串,每次询问x号串和y号串的最长公共子串的长度,这个子串必须是n个串中某个串的前缀 ...

  8. 2017多校第8场 HDU 6134 Battlestation Operational 莫比乌斯反演

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6134 题意: 解法: 那么g(n)怎么求,我们尝试打表发现g(n)是有规律的,g(n)=g(n-1)+ ...

  9. 2017多校第7场 HDU 6129 Just do it 找规律

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6129 题意:求a序列后m次xor前缀和 解法: 手动对1位置对每个位置的贡献打表发现 第一次 贡献为 ...

随机推荐

  1. visual Studio 2017 扩展开发(一)《向Visual Studio菜单栏新增一个菜单》

    最近有接触到关于visual studio 2017 扩展的开发,特此记录,也是为了督促自己去深入了解其原理. 开始开发Visual Studio 扩展,在这里我安装了visual studio 20 ...

  2. 51nod_1627:瞬间移动

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1627 还是杨辉三角~ #include<bits/st ...

  3. 天地图使用过程中由于display:none导致加载部分地图瓦片失败

    在为按钮添加点击事件让地图显示的时候,初始加载未加载到当前页面尺寸的所有地图瓦片,在display:none之后停止加载地图,所以display:none属性去掉,改为dom解析完成之后$('#map ...

  4. Python蜕变-2017-4-23

    我的第一篇博客,这是试水练习.这次上的菜是Haporxy配置文件操作. <1> 上需求: 具体配置文件如下: global log 127.0.0.1 local2 daemon maxc ...

  5. 【ES6】变量的解构赋值

    1. 数组 var [a, b, c] = [1, 2, 3]; let [a, [b], d] = [1, [2, 3], 4]; 默认值生效的条件是,对象的属性值严格等于undefined. [x ...

  6. 【流量】netflow 基础知识

    摘要 记录下关于netflow的基础知识以及应用,现状 是什么 一种数据交换方式,NetFlow流量统计数据包括数据流时戳 源IP地址和目的IP地址 源端口号和目的端口号 输入接口号和输出接口号 下一 ...

  7. 让初学者快速了解Git

    Git工作原理 为了更好的学习Git,我们们必须了解Git管理我们文件的3种状态,分别是已提交(committed).已修改(modified)和已暂存(staged),由此引入 Git 项目的三个工 ...

  8. 构建 MariaDB Galera Cluster 分布式数据库集群(二)

    MariaDB的安装 构建 MariaDB Galera Cluster之前,首先安装MariaDB,本文使用的版本是10.1 1.环境准备 主机: MariaDB01(192.168.56.102) ...

  9. 【RegExp】JavaScript中正则表达式判断匹配规则以及常用方法

    字符串是编程时涉及到的最多的一种数据结构,对字符串进行操作的需求几乎无处不在. 正则表达式是一种用来匹配字符串的强有力的武器.它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符 ...

  10. 4G内存服务器的MySQL配置优化

    公司网站访问量越来越大(日均超10万PV),MySQL自然成为瓶颈,关于 MySQL 的优化,最基本的是 MySQL 系统参数的优化. MySQL对于web架构性能的影响最大,也是关键的核心部分.My ...