题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6178
题意:给定一颗树有n个节点,有k个猴子,每个猴子在一个节点上,并且每个节点只能有一只猴子。要求砍掉一些边,使得每只猴子至少与一只猴子有边相连,求剩余的最少的边。
题解:因为一条边可以放两只猴子,那么先让猴子成对的站边,两两配对。如果猴子还有剩余的,那每个猴子需要一条边加入到已经成对的猴子中去。先进行一次dfs,求出可以成对的猴子,在与总数比较即可。
没有想到就是很糟糕~
需要用到读入挂,算法是o(n)的,但是输入数据太多,用到fread
#include <stdio.h> #include <algorithm> #include <math.h> #include <string.h> #include <vector> #include <queue> #include <stack> #include <iostream> #define pi acos(-1.0) #define INF 0x3f3f3f3f using namespace std; #define ll long long const int maxn=100010; vector<int>e[maxn]; int vis[maxn],cnt; inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline ll _read(){ char ch=nc();ll 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 fa) { for(int i=0;i<e[x].size();i++) { if(e[x][i]==fa) continue; dfs(e[x][i],x); if(!vis[e[x][i]]&&!vis[x]) { cnt++; vis[e[x][i]]=vis[x]=1; } } } int main() { //freopen("C:\Users\Administrator\Desktop\a.txt","r",stdin); //ios::sync_with_stdio(false); //freopen("C:\Users\Administrator\Desktop\b.txt","w",stdout); int T; int n,k,a; T=_read(); while(T--) { n=_read(),k=_read(); memset(vis,0,sizeof vis); cnt=0; for(int i=0;i<=n;i++) e[i].clear(); for(int i=1;i<n;i++) a=_read(),e[i+1].push_back(a),e[a].push_back(i+1); dfs(1,-1); if(2*cnt>=k) printf("%d ",(k+1)/2); else printf("%d ",k-cnt); } return 0; }