HDU 6178 Monkeys (二分图匹配)

Description

给出一棵\(n\)个结点的无向树,问要使图中有\(k\)个点不是孤立点所需的最少的边的数量。

Input

第一行给出用例组数\(T\),对于每组用例,第一行给出两个整数\(n\)\(k\),第二行给出\(n-1\)个数,分别表示\(2\)\(n\)号结点的父节点。\(1 \leqslant T \leqslant 100\)\(2 \leqslant k \leqslant n \leqslant 10^5\)

Output

对于每组用例输出一个整数,表示需要的最少的边的数量。

Sample Input

2
4 4
1 2 3
4 3
1 1 1

Sample Output

2
2

Solution

一个点,只要与任意一个点相连,这个点就不是孤立点。要用最少的边,就要考虑边的利用率。最大的利用率是一条边使得两个孤立点变得不孤立,如果一条边连接了一个孤立点和一个原来不孤立的点,可以认为这个点只贡献了\(1\)。因此我们想要尽可能多的连接两个孤立点的边,这就是求一棵树上的最大匹配,因为树也是一种特殊的二分图。求出最大匹配之后判断一下与\(k\)的关系输出答案。

树上的二分图最大匹配可以一遍DFS从树叶到树根贪心解决。另外这道题输入卡常数,要用快速读入。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
const int M = 1e5 + 10;

namespace fastIO 
{
    #define BUF_SIZE 100000
    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');
    }
    inline void readc(char &x)
    {
        char ch;
        while(blank(ch=nc()));
        if(IOerror)return;
        x=ch;
    }
    inline void reads(char *x,int n)
    {
        char ch;
        while(blank(ch=nc()));
        if(IOerror)return;
        for(int i=0;i<n;i++,ch=nc())x[i]=ch;
        x[n]='\0';
    }
    #undef BUF_SIZE
};
using namespace fastIO;

struct Edge
{
    int to, next;
} edge[2 * M];
int adj[N], no;

void init()
{
    memset(adj, -1, sizeof(adj));
    no = 0;
}

void add(int u, int v)
{
    edge[no].to = v;
    edge[no].next = adj[u];
    adj[u] = no++;
}

int ans;
int dfs(int u, int f)
{
    int s = 0;
    for (int i = adj[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if (v == f) continue;
        s += dfs(v, u);
    }
    if (s) { ans++; return 0; }
    return 1;
}

int main()
{
    int T;
    read(T);
    while (T--)
    {
        int n, k;
        read(n); read(k);
        init();
        for (int i = 1; i < n; i++)
        {
            int f;
            read(f);
            add(i + 1, f); add(f, i + 1);
        }
        ans = 0;
        dfs(1, 1);
        if (k % 2 == 0)
        {
            if (k / 2 <= ans) printf("%d\n", k / 2);
            else printf("%d\n", ans + k - ans * 2);
        }
        else
        {
            if (k - 1 <= ans * 2) printf("%d\n", (k - 1) / 2 + 1);
            else printf("%d\n", ans + k - ans * 2);
        }
    }
    return 0;
}

http://acm.hdu.edu.cn/showproblem.php?pid=6178

posted @ 2017-08-24 22:13  达达Mr_X  阅读(130)  评论(0编辑  收藏  举报