您的位置:首页 > 其它

HDU - 6178 Monkeys(DFS+究极输入外挂)

2017-08-24 23:55 260 查看


Monkeys

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

 

题意:给你一棵树,要你求最少的边使得所有猴子都有任意一个同伴,有边相连即为同伴。

解题思路:很容易就会想到,两两配对是最优的。因此只要深搜这棵树,将所有可以两两配对的结点两两配对(有些结点可能有相同的祖先,所以不能配对),然后求出最多可以占多少个节点。然后再分情况讨论,详细看代码注释。

另外这题要开究极输入外挂……本地不能调试那种……fread外挂才能过……TLE到怀疑人生……也有可能是我算法不够优吧

#include<iostream>
#include<deque>
#include<memory.h>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<vector>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#define INF (1LL<<62)
#define ll long long int
using namespace std;

/*究极输入外挂*/
namespace fastIO {
#define BUF_SIZE 100000
// fread -> read
bool IOerror = 0;

char nc() {
static char buf[BUF_SIZE], *pl = buf + BUF_SIZE, *pr = buf + BUF_SIZE;
if(pl == pr) {
pl = buf;
pr = buf + fread(buf, 1, BUF_SIZE, stdin);
if(pr == pl) {
IOerror = 1;
return -1;
}
}
return *pl++;
}

inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}

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;
/*究极输入外挂*/

int v2[200005],nxt[200005];

int head[200005];

int edge_num;
void insert_edge(int v,int u){
v2[edge_num]=u;
nxt[edge_num]=head[v];
head[v]=edge_num++;
}
int N,K,temp;
bool vis[200005];
int ans;

//深搜配对
void dfs(int v,int par){

for(int i=head[v];~i;i=nxt[i]){
//如果不是指向父亲的边
if(v2[i]!=par){
dfs(v2[i],v);//往下搜

//并且都没有配对过
if(!vis[v2[i]]&&!vis[v]){
vis[v]=vis[v2[i]]=true;
ans+=2;//占点数+2
}
}
}
}

int main()
{
int t;
read(t);
while(t--){
read(N);
read(K);

memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
edge_num=0;

for(int i=2;i<=N;i++){
read(temp);
insert_edge(i,temp);
insert_edge(temp,i);
}

ans=0;//存最多可以占多少个点
dfs(1,0);

//如果配对数比K小,那么肯定只能占
if(ans<K)
ans=K-ans/2;//实际上是ans/2+K-ans,意思是先把点占满最少要ans/2条边,然后每多一个猴子,就要多占一条边。
else if(K&1)//K要区分奇偶
ans=K/2+1;
else
ans=K/2;

printf("%d\n",ans);

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: