hdu 6178 dfs+超神读入挂

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
 

Source
 

Recommend

liuyiding   |   We have carefully selected several similar problems for you:  6181 6180 6179 6178 6177 


题意:给出一棵树,有n个节点,树上要安排k只猴子,要求每只猴子至少要与一直其他的猴子相邻问树上最少留多少条边能按照要求安排好这些猴子


思路:其实我们只需要找这颗树上最多有多少条不相交的边就可以了,因为我们贪心的策略肯定是最好是一条边对应两只猴子,所以我们只要找到最多的边数ans,如果ans*2<k的话,剩下的猴子就只能是一直猴子对应一条边喽


找最多的边我们就从树根开始找,如果一个父亲节点vis=0,并且他的子节点经过深搜从叶子节点回溯回来的vis还是0那么这就是一条边


ac代码:

#include <bits/stdc++.h>
namespace fastIO{
    #define BUF_SIZE 100000000
    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;
using namespace std;

const int maxn=100000+10;

int T;
int N,K;
int ans=0;

struct Edge{
    int to;
    int next;
}edge[2*maxn];

int cntE=0;
int head[maxn];
bool vis[maxn];

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

bool dfs(int x){
    bool flag=false;
    for (int i=head[x];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if (vis[v]) continue;
        vis[v]=true;
        if (dfs(v))
            flag=true;
    }
    if (flag){
        ans++;
        return false;
    }
    else
        return true;
}
int main(){
    read(T);
    while (T--){
        memset(head,-1,sizeof(head));
        memset(vis,false,sizeof(vis));
        cntE=0;
        read(N);
        read(K);
        for (int i=1;i<=N-1;i++){
            int x;
            read(x);
            addedge(x,i+1);
        }
        ans=0;
        vis[1]=1;
        dfs(1);
        if (2*ans<=K){
            printf("%d\n",ans+K-2*ans);
        }
        else
            printf("%d\n",(K-1)/2+1);
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值