HDU6178 Monkeys

题目

Monkeys

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


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
 
题目大意

  先不写

解题思路

  自己蠢的一比,赛后看数据,100组错了4个,还是最简单那种,竟然还没考虑到,fread都会用了,死在一个小错误上,悲伤逆流成河
  看懂了就是一个dfs,找有多少个匹配对,如果找到了一个匹配对,就把这两个节点标记上表示已经用过了,dfs的时候从出入度为2的点进入,
出入度1的点先预处理一下,如果不预处理会出现一个匹配出错


如果从1进来,1和2匹配,这时候到了3,如果3和4匹配那我么很高兴,但是如果3和5匹配那么就出错了,这就是要预处理的原理
 
 
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int T,n,k,par[N],sz[N];
int ans[N];
int vis[N];
int num;
bool pa[N];
vector<int> e[N];
inline char nc(){
    static char buf[100000+10],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000+10,stdin),p1==p2)?EOF:*p1++;
}
inline int _read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
void dfs(int x,int cnt,int fa)
{
    if(vis[x])
        return ;
    vis[x]=1;
    cnt++;
    if(cnt==2)
    {
        if(!pa[x]&&!pa[fa])
       {
        pa[x]=1;
        pa[fa]=1;
        num++;
        cnt=0;
       }
       else if(pa[x]==0)
       {
           //vis[x]=0;
           cnt=1;
       }
       // return true;
    }
    for(auto &v:e[x])
    {
        if(!vis[v])
        {
           dfs(v,cnt,x);
               //break;
        }
    }

}
int main()
{
   // freopen("1008.in", "r", stdin);
   // freopen("data.out", "w", stdout);
    T =_read();
    while(T--)
    {
      num=0;
      n=_read();
      k=_read();
      memset(ans,0,sizeof(ans));
      memset(vis,0,sizeof(vis));
      memset(pa,0,sizeof(pa));
      e[1].clear();
        for(int i=2; i<=n; i++)
          {
               par[i] = _read();
               e[i].clear();
               e[i].push_back(par[i]);
               e[par[i]].push_back(i);
               ans[i]++;
               ans[par[i]]++;
          }
        for(int i=1;i<=n;i++)
        {
           if(ans[i]==1&&!vis[i]&&!vis[e[i][0]])
            {
                vis[i]=1;
                pa[i]=1;
                vis[e[i][0]]=1;
                pa[e[i][1]];
                num++;
            }
        }
        for(int i=1;i<=n;i++)
        {
            if(ans[i]==2&&!vis[i])
            {
                dfs(i,0,0);
            }
        }
        int od=k/2;
        if(k&1)
        {
            if(num>=od)
                printf("%d\n",od+1);
            else
            {
                printf("%d\n", k-2*num+num);
            }
        }
        else
        {
            if(num>=od)
               printf("%d\n",od);
            else
            {
                printf("%d\n", k-2*num+num);
            }
        }
    }
    return 0;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值