【赛后补题】(HDU6228) Tree {2017-ACM/ICPC Shenyang Onsite}

这条题目当时卡了我们半天,于是成功打铁……今天回来一看,mmp,贪心思想怎么这么弱智。。。。。(怪不得场上那么多人A了

题意分析

这里是原题:

Tree

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)

Problem Description
Consider a un-rooted tree T which is not the biological significance of tree or plant, but a tree as an undirected graph in graph theory with n nodes, labelled from 1 to n. If you cannot understand the concept of a tree here, please omit this problem.
Now we decide to colour its nodes with k distinct colours, labelled from 1 to k. Then for each colour i = 1, 2, · · · , k, define Ei as the minimum subset of edges connecting all nodes coloured by i. If there is no node of the tree coloured by a specified colour i, Ei will be empty.
Try to decide a colour scheme to maximize the size of E1 ∩ E2 · · · ∩ Ek, and output its size.

Input
The first line of input contains an integer T (1 ≤ T ≤ 1000), indicating the total number of test cases.
For each case, the first line contains two positive integers n which is the size of the tree and k (k ≤ 500) which is the number of colours. Each of the following n - 1 lines contains two integers x and y describing an edge between them. We are sure that the given graph is a tree.
The summation of n in input is smaller than or equal to 200000.

Output
For each test case, output the maximum size of E1 ∩ E1 … ∩ Ek.

Sample Input
3
4 2
1 2
2 3
3 4
4 2
1 2
1 3
1 4
6 3
1 2
2 3
3 4
3 5
6 2

Sample Output
1
0
1

题意很简单,我们考虑一下做法。
要想交集尽可能大,颜色各自的分布应该尽可能“往顶层和底层分布”——这是贪心思想。然后具体怎么实现?很简单,对每一个点 i ,设它的子树的节点(包括它自身)有p个,那么只需要检查 pk npk 即可。不需要查边,只需要查点,因为只要存在这样的点,那么一定存在这样的一条公共边。
实现查子树可以用dfs遍历一遍即可实现。

代码

#include <bits/stdc++.h>

using namespace std;
#define NQUICKIO
#define NFILE

struct Edge
{
    int u,v;
    Edge(int _u,int _v):u(_u),v(_v) {}
};
const int maxnode=200005;
vector<Edge> edges;
vector<int> G[maxnode];
int s[maxnode];
void addEdge(int u,int v)
{
    edges.push_back(Edge(u,v));
    G[u].push_back((int)edges.size()-1);
    return;
}

int dfs(int f,int p)
{
    //cout<<"now point:"<<p<<endl;
    int nowsum=1;
    for(int i=0;i!=(int)G[p].size();++i)
        if(edges[G[p][i]].v!=f)
            nowsum+=dfs(p,edges[G[p][i]].v);
    return s[p]=nowsum;
}

int main()
{
#ifdef QUICKIO
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
#endif
#ifdef FILE
    freopen("datain.txt","r",stdin);
    freopen("dataout.txt","w",stdout);
#endif
    int T; cin>>T;
    while(T--)
    {
        edges.clear();
        int n,k; cin>>n>>k;
        for(int i=1;i<=n;++i) G[i].clear();
        memset(s,0,sizeof(s));
        for(int i=1;i!=n;++i)
        {
            int tu,tv; cin>>tu>>tv;
            addEdge(tu,tv);
            addEdge(tv,tu);
        }
        dfs(-1,edges[0].u);
        int ans=0;
        /*for(int i=1;i<=n;++i)
            cout<<s[i]<<" ";
            cout<<endl;*/
        for(int i=1;i<=n;++i)
        {
            if(s[i]>=k && n-s[i]>=k) ans++;
        }
        cout<<ans<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值