http://acm.hdu.edu.cn/showproblem.php?pid=6178
【题意】
- 给定一棵有n个结点的树,现在有k个猴子分布在k个结点上,我们可以删去树上的一些边,使得k个猴子每个猴子都至少和其他一个猴子相连
- 问树上最少保留多少条边
【思路】
- 每个猴子要至少和一个猴子相连,考虑保留的边最少,那么最优的情况一定是一条边的两个顶点放两个猴子,这些边的顶点都不重合
- 我们现在要找到给定的树中最多有多少条这样的边,即最大二分匹配
- O(n)的DFS,对于每个结点,优先与叶子结点形成一条边
【AC】
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 namespace IO 5 { 6 const int MX=1e8; 7 char buf[MX]; 8 int c,sz; 9 void begin() 10 { 11 c=0; 12 sz=fread(buf,1,MX,stdin); 13 } 14 inline bool read(int &x) 15 { 16 while(c<sz && buf[c]!='-' && (buf[c]<'0'||buf[c]>'9')) ++c; 17 if(c>=sz) return false; 18 bool flag=0; 19 if(buf[c]=='-') flag=1,++c; 20 for(x=0;c<sz&&buf[c]>='0'&&buf[c]<='9';++c) 21 x=x*10+buf[c]-'0'; 22 if(flag) x=-x; 23 return true; 24 } 25 } 26 27 int n,k; 28 const int maxn=1e5+2; 29 const int maxm=maxn*2; 30 bool vis[maxn]; 31 struct edge 32 { 33 int to; 34 int nxt; 35 }e[maxm]; 36 int head[maxn]; 37 int tot; 38 //int dp[maxn][2]; 39 int flag; 40 int cnt; 41 void init() 42 { 43 memset(head,-1,sizeof(head)); 44 tot=0; 45 // memset(dp,0,sizeof(dp)); 46 memset(vis,false,sizeof(vis)); 47 cnt=0; 48 } 49 void addedge(int u,int v) 50 { 51 e[tot].to=v; 52 e[tot].nxt=head[u]; 53 head[u]=tot++; 54 } 55 56 void dfs(int u,int pa) 57 { 58 for(int i=head[u];i!=-1;i=e[i].nxt) 59 { 60 int v=e[i].to; 61 if(v==pa) continue; 62 dfs(v,u); 63 if(!vis[u]&&!vis[v]) 64 { 65 cnt++; 66 vis[u]=vis[v]=true; 67 } 68 } 69 } 70 int main() 71 { 72 IO::begin(); 73 int T; 74 IO::read(T); 75 // scanf("%d",&T); 76 while(T--) 77 { 78 init(); 79 // scanf("%d%d",&n,&k); 80 IO::read(n);IO::read(k); 81 int x; 82 for(int i=2;i<=n;i++) 83 { 84 //scanf("%d",&x); 85 IO::read(x); 86 addedge(i,x); 87 addedge(x,i); 88 } 89 dfs(1,-1); 90 int tmp=cnt*2; 91 int ans; 92 if(k<=tmp) 93 { 94 ans=k/2; 95 if(k%2) ans++; 96 } 97 else 98 { 99 ans=cnt+k-tmp; 100 } 101 printf("%d\n",ans); 102 } 103 return 0; 104 }