hdu 6178 Monkeys (dfs+FastIO)

Monkeys

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 153428/153428 K (Java/Others)
Total Submission(s): 1307    Accepted Submission(s): 431


Problem Description
There is a tree having N vertices. In the tree there are K monkeys (K <= N). A vertex can be occupied by at most one monkey. They want to remove some edges and leave minimum edges, but each monkey must be connected to at least one other monkey through the remaining edges.
Print the minimum possible number of remaining edges.
 

Input
The first line contains an integer T (1 <= T <= 100), the number of test cases.
Each test case begins with a line containing two integers N and K (2 <= K <= N <= 100000). The second line contains N-1 space-separated integers a1,a2,,aN1 , it means that there is an edge between vertex ai and vertex i+1 (1 <= ai <= i).
 

Output
For each test case, print the minimum possible number of remaining edges.
 

Sample Input
  
  
2 4 4 1 2 3 4 3 1 1 1
 

Sample Output
  
  
2 2
 

题意:
让你尽可能留下少的边,使得每只猴子都不孤立(即每只猴子至少与与一只猴子相连),输出边数

解析:
  尽可能让两只猴子独立地连在一起,这样可以使边最少,当有奇数个猴子时,就使一堆是3个猴子连在一起
这样用dfs深搜,找树中最多有多少个两个连在一起(即匹配)的堆,奇数时还要找一个3个匹配的堆

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;


namespace fastIO {
#define BUF_SIZE 1000000
    //fread -> read
    bool IOerror = 0;
    inline char nc() {
        static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
        if(p1 == pend) {
            p1 = buf;
            pend = buf + fread(buf, 1, BUF_SIZE, stdin);
            if(pend == p1) {
                IOerror = 1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch) {
        return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
    }
    inline void read(int &x) {
        char ch;
        while(blank(ch = nc()));
        if(IOerror)
            return;
        for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
    }
#undef BUF_SIZE
};
using namespace fastIO;


const int MAXN = 2e5;

typedef struct node
{
	int u;
	int v;
	int next;
}node;

node edge[MAXN];
int head[MAXN],cnt;
int flag;

int n,k,num3,num2;

void addedge(int u,int v)
{
	edge[cnt].u=u;
	edge[cnt].v=v;
	edge[cnt].next=head[u];
	head[u]=cnt++;
}

int dfs(int x)   //dfs返回在待匹配(前提是能跟上一层匹配)的结点的数量
{
	if(head[x]==-1)
	{
		return 1;
	}
	int num=0;
	for(int i=head[x];i!=-1;i=edge[i].next)
	{
		int v=edge[i].v;
		num+=dfs(v);
	}
	if(flag&&num>=2)   //奇数,找一个有3个节点的堆
	{
		num3=1;
		flag=0;
		return 0;
	}
	if(num==0)
	{
		return 1;
	}
	else
	{
		num2++;
		return 0;
	}

}

int main()
{
	int t;
	//scanf("%d",&t);
	read(t);
	while(t--)
	{
		memset(head,-1,sizeof(head));
		cnt=0;
		//scanf("%d%d",&n,&k);
		read(n);read(k);
		for(int i=0;i<n-1;i++)
		{
			int tmp;
			read(tmp);
			//scanf("%d",&tmp);
			addedge(tmp,i+2);
		}
		if(k&1) flag=1;
		else flag=0;
		num3=num2=0;
		dfs(1);

		if(k&1)
		{
			if(num3==0)
			{
				if((k-1)>num2*2)
				{
					printf("%d\n",num2+k-num2*2);
				}
				else
				{
					printf("%d\n",(k-1)/2+1);
				}
			}
			else
			{
				if((k-3)>num2*2)
				{
					printf("%d\n",num3*2+num2+k-num2*2-num3*3);
				}
				else
				{
					printf("%d\n",(k-3)/2+2);
				}
			}
		}
		else
		{
			if(k>num2*2)
			{
				printf("%d\n",num2+k-num2*2);
			}
			else
			{
				printf("%d\n",k/2);
			}
		}

	}
	return 0;

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值