HDU6178-Monkeys

探讨了在一棵树上,通过移除部分边使每只猴子至少与其他一只猴子保持连接的情况下,剩余边数最少的问题。使用深度优先搜索算法找到解决方案。

Monkeys

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

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,…,aN−1, 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
2017 Multi-University Training Contest - Team 10

题目大意:给出一棵树和 k 个猴子,砍掉一些边,每只猴子至少要与另一只猴子直接相连,问最后剩的边数最少为多少?
解题思路: dfs遍历一遍,若后继有未被标记的点,则可与后继相连,这样就得出了最大的匹配个数,然后跟 k 比较一下。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<fstream>
using namespace std;
const int MAXN=1e5+5;
const int INF=0x3f3f3f3f;
bool vis[MAXN];
int ans,tot,head[MAXN];

namespace fastIO {
    #define BUF_SIZE 100000
    //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;

struct Edge
{
    int to,nxt;
}e[MAXN*2];

void addedge(int u,int v)
{
    e[tot].to=v;
    e[tot].nxt=head[u];
    head[u]=tot++;
}

void dfs(int u,int fa)
{
    int son=0,mon=0;
    for(int i=head[u];i!=-1;i=e[i].nxt)
    {
        int to=e[i].to;
        if(to==fa) continue;
        dfs(to,u);
        son++;
        if(vis[to]) mon++;
    }
    if(son>mon) vis[u]=true,ans++;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int T;
    read(T);
    //scanf("%d",&T);
    int n,k;
    while(T--)
    {
        memset(head,-1,sizeof(head));
        memset(vis,false,sizeof(vis));
        tot=0;
        read(n);read(k);
        //scanf("%d%d",&n,&k);
        int tmp;
        for(int i=2;i<=n;i++)
        {
            read(tmp);
            //scanf("%d",&tmp);
            addedge(tmp,i);addedge(i,tmp);
        }
        ans=0;
        dfs(1,-1);
        if(2*ans>=k)
        {
            if(k&1) printf("%d\n",(k-1)/2+1);
            else printf("%d\n",k/2);
        }else
        {
            printf("%d\n",ans+(k-2*ans));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值