• Comet OJ


    题意: 给定一颗无向无根树,求一大小为K的联通子图使得非子图最远点距离子图距离最小


    树, 且联通

    考虑平均砍去部分子树使得答案最优即可

    所以从叶子入手一层一层往里砍, 砍几层答案是几

    那么需要记录信息 p[y] 为以 y 为跟的子树最大深度为多少以 y 为根的子树最大深度为多少

    所以要找个根,当树的中心为根时 p[y]最平均

    所以两遍dfs求树中心即可

    用树中心树上dp子树最大深度,

    按深度遍历累加 当累加树达到时直接输出就完了。

    如图 留3个时 ,树中心为1,红圈里的答案最优。

    代码


    /*
        Zeolim - An AC a day keeps the bug away
    */
     
    //pragma GCC optimize(2)
    //#pragma GCC ("-W1,--stack=128000000")
    #include <bits/stdc++.h>
    using namespace std;
    #define mp(x, y) make_pair(x, y)
    #define fr(x, y, z) for(int x = y; x < z; ++x)
    typedef long long ll;
    typedef double ld;
    typedef std::pair<int, int> pii;
    typedef std::vector <int> vi;
    //typedef __int128 ill;
    const ld PI = acos(-1.0);
    const ld E = exp(1.0);
    const ll INF = 0x3f3f3f3f3f3f3f3f;
    const ll MOD = 1e9 + 7;
    const int MAXN = 1e6 + 10;
    
    vector <int> edge[MAXN];
    
    int n, k;
    
    int p[MAXN] = {0}, cnt[MAXN] = {0}, in[MAXN] = {0};
    
    int lst = -1, lstlen = -1, rot = -1;
    
    bitset <MAXN> used;
    
    void dfs(int now, int step)
    {
    	used[now] = true;
    	
    	if(step > lstlen)
    		lstlen = step, lst = now;
    		
    	for(auto x : edge[now])
    	{
    		if(!used[x])
    			dfs(x, step + 1);
    	}
    	
    	used[now] = false;
    }
    
    void gao1(int now, int step)
    {
    	used[now] = true;
    	
    	p[step] = now;
    	
    	if(step > lstlen)
    		lstlen = step, lst = now, rot = p[step / 2];
    		
    	for(auto x : edge[now])
    	{
    		if(!used[x])
    			gao1(x, step + 1);
    	}
    	
    	used[now] = false;
    }
    
    void xiagao(int now, int fa)
    {
    	used[now] = true;
    		
    	for(auto x : edge[now])
    	{
    		if(!used[x])
    			xiagao(x, now);
    	}
    	
    	p[fa] = max(p[fa], p[now] + 1);
    	
    	used[now] = false;
    }
    
    void gao()
    {
    	used.reset();
    	dfs(1, 0);
    	
    	used.reset();
    	int nb = lst;
    	
    	lst = lstlen = -1;
    	gao1(nb, 0);
    	
    	fill(p, p + n + 10, 1);
    	used.reset();
    	
    	xiagao(rot, 0);
    	
    	for(int i = 1; i <= n; ++i)
    		++cnt[p[i]];
    		
    	int sum = 0;
    	
    	for(int i = 1; i <= n; ++i)
    	{
    		sum += cnt[i];
    		
    		if(sum >= n - k)
    		{
    			cout << i << '
    ';
    			return ;
    		}
    	}
    }
    
    
    int main()
    {  
    	ios::sync_with_stdio(0);
    	cin.tie(0); cout.tie(0);
    	//freopen("d:out.txt","w",stdout);
    	//freopen("in.txt","r",stdin);
    	
    	cin >> n >> k;
    	
    	for(int i = 1, x, y; i < n; ++i)
    	{
    		cin >> x >> y;
    		
    		edge[x].push_back(y);
    		++in[x], ++in[y];
    		edge[y].push_back(x);
    	}
    	
    	gao();
    	
        return 0;
    }
    /*
    6 1
    1 2
    2 3
    2 4
    1 5
    5 6
    */

    后来发现求p也不用那么麻烦找中心,

    可以用拓扑从叶子入手一层一层进行dp求p数组

    这样也是均匀的

    其他一样

    /*
        Zeolim - An AC a day keeps the bug away
    */
     
    //pragma GCC optimize(2)
    //#pragma GCC ("-W1,--stack=128000000")
    #include <bits/stdc++.h>
    using namespace std;
    #define mp(x, y) make_pair(x, y)
    #define fr(x, y, z) for(int x = y; x < z; ++x)
    typedef long long ll;
    typedef double ld;
    typedef std::pair<int, int> pii;
    typedef std::vector <int> vi;
    //typedef __int128 ill;
    const ld PI = acos(-1.0);
    const ld E = exp(1.0);
    const ll INF = 0x3f3f3f3f3f3f3f3f;
    const ll MOD = 1e9 + 7;
    const int MAXN = 1e6 + 10;
    
    vector <int> edge[MAXN];
    
    int n, k;
    
    int p[MAXN] = {0}, cnt[MAXN] = {0}, in[MAXN] = {0};
    
    
    void gao()
    {
    	queue <int> Q;
    	
    	for(int i = 1; i <= n; ++i)
    	{
    		if(in[i] == 1)
    			Q.push(i), p[i] = 1;
    	}
    	
    	while(!Q.empty())
    	{
    		int now = Q.front();
    		Q.pop();
    		for(auto x : edge[now])
    		{
    			if(in[x] == 1) continue; //已经算过的叶子要直接跳过 不然影响p数组更新
    			
    			p[x] = max(p[x], p[now] + 1);
    			
    			if(--in[x] == 1) //无向图 入度为 1 即为叶子
    				Q.push(x);
    		}	
    	}
    	
    	for(int i = 1; i <= n; ++i)
    		++cnt[p[i]];
    		
    	int sum = 0;
    	
    	for(int i = 1; i <= n; ++i)
    	{
    		sum += cnt[i];
    		
    		if(sum >= n - k)
    		{
    			cout << i << '
    ';
    			return ;
    		}
    	}
    }
    
    int main()
    {  
    	ios::sync_with_stdio(0);
    	cin.tie(0); cout.tie(0);
    	//freopen("d:out.txt","w",stdout);
    	//freopen("in.txt","r",stdin);
    	
    	cin >> n >> k;
    	
    	for(int i = 1, x, y; i < n; ++i)
    	{
    		cin >> x >> y;
    		
    		edge[x].push_back(y);
    		++in[x], ++in[y];
    		edge[y].push_back(x);
    	}
    	
    	gao();
    	
        return 0;
    }
    /*
    6 1
    1 2
    2 3
    2 4
    1 5
    5 6
    */
  • 相关阅读:
    Spring IoC
    Java软件安装
    Struts(一)
    Struts(二)
    Hibernate(六)
    Hibernate(五)
    Hibernate(二)
    Hibernate(四)
    Hibernate(三)
    Hibernate(一)
  • 原文地址:https://www.cnblogs.com/zeolim/p/12270348.html
Copyright © 2020-2023  润新知