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;
}