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 }
贪心,优先选叶子结点

相关文章:

  • 2021-11-24
  • 2022-12-23
  • 2022-12-23
  • 2022-02-01
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-10-24
  • 2022-12-23
  • 2022-02-10
  • 2021-12-17
  • 2021-11-03
  • 2021-06-15
相关资源
相似解决方案