hdu 7136 Jumping Monkey (并查集,重构树)

hdu 7136 Jumping Monkey

分析:

  • 并查集+重构树

  • 可以想到 B F S BFS BFS 去遍历,每次从当前权值最大点出发跑一遍 B F S BFS BFS,经过的点的 d e p + + dep++ dep++

    然后,便将权值最大点去掉,继续重复上一个操作

    但是,这样显然会 T T T(代码见下文)

  • 考虑如何优化?(从比赛开始到结束,也没想出怎么优化)

    n n n 遍 B F S BFS BFS ,过程有很多步是重复的

    如果这棵树以权值最大点为根,从上到下的权值是递减的,那答案就是每个节点的深度(这就很 n i c e nice nice )

  • 如何重构这棵树?

    考虑普遍情况和上述的特殊情况,区别在哪?

    区别就在于:普遍情况并非严格递减的

    要有一种重构的方法,将这棵树变成特殊情况的,且还不会影响最终答案

  • 重构方法

    按点权从小到大枚举结点 u u u ,并将 u u u 作为所有与 u u u 相连的(已经枚举过的)连通块的根(这里要用并查集维护)

    从而建立一棵新树,每个结点的深度(根的深度为 1 1 1 )即是答案。

    重构方法的正确性,多画几张图就能理解了~

#include <bits/stdc++.h>
using namespace std;

const int N=1e5+5;
inline int read()
{
	int x=0,f=1; char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();}
	while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
	return f*x;
}
struct Node
{
    int next,to;
}e[N<<1];
int head[N],tot;
inline void add(int u,int v)
{
    e[++tot].next=head[u];
    e[tot].to=v;
    head[u]=tot;
}
struct graph
{
    int w,id;
    bool operator <(const graph &a) const { return w<a.w; }
}b[N];
int f[N];
int fd(int k) { return f[k]==k ? k : f[k]=fd(f[k]); }
vector <int> g[N];
int dep[N];
void dfs(int u)
{
    for(auto v : g[u])
    {
        dep[v]=dep[u]+1;
        dfs(v);
    }
}
int vis[N];
signed main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        n=read();
        tot=0;
        for(int i=1;i<=n;i++) 
        { 
            f[i]=i; g[i].clear(); dep[i]=vis[i]=head[i]=0;
        }
        for(int i=1;i<n;i++)
        {
            int u,v;
            u=read(); v=read();
            add(u,v);
            add(v,u);
        }
        for(int i=1;i<=n;i++)
        {
            b[i].w=read();
            b[i].id=i;
        }
        sort(b+1,b+1+n);
        vis[b[1].id]=1;
        for(int i=2;i<=n;i++)
        {
            int u=b[i].id;
            for(int i=head[u]; i ;i=e[i].next)
            {
                int v=e[i].to;
                if(vis[v])
                {
                    int y=fd(v); // 找到连通块的祖宗
                    f[y]=u;
                    g[u].push_back(y); // 重构树
                }
            }
            vis[u]=1; //要维护的集合里加入该点
        }
        dep[b[n].id]=1;
        dfs(b[n].id);
        for(int i=1;i<=n;i++) printf("%d\n",dep[i]);       
    }
    return 0;
}

BFS (T了的)

#include <bits/stdc++.h>
using namespace std;

const int N=1e5+5;
inline int read()
{
	int x=0,f=1; char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();}
	while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
	return f*x;
}
struct Node
{
    int next,to;
}e[N<<1];
int head[N],tot;
inline void add(int u,int v)
{
    e[++tot].next=head[u];
    e[tot].to=v;
    head[u]=tot;
}
struct graph
{
    int w,id;
    bool operator <(const graph &a) const { return w>a.w; }
}b[N];
int dep[N];
int vis[N],vis1[N];
signed main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        n=read();
        tot=0;
        for(int i=1;i<=n;i++) 
        { 
            dep[i]=vis[i]=head[i]=0;
        }
        for(int i=1;i<n;i++)
        {
            int u,v;
            u=read(); v=read();
            add(u,v);
            add(v,u);
        }
        for(int i=1;i<=n;i++)
        {
            b[i].w=read();
            b[i].id=i;
        }
        sort(b+1,b+1+n);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++) vis1[j]=0;
            queue <int> q;
            q.push(b[i].id);
            dep[b[i].id]+=1;
            vis[b[i].id]=1; // 去掉当前点
            vis1[b[i].id]=1;
            while(!q.empty())
            {
                int u=q.front();
                q.pop();
                for(int j=head[u]; j ;j=e[j].next)
                {
                    int v=e[j].to;
                    if(vis[v] || vis1[v]) continue;
                    dep[v]+=1;
                    q.push(v);
                    vis1[v]=1;
                }
            }
        }
        for(int i=1;i<=n;i++) printf("%d\n",dep[i]); 
    }
    return 0;
}
上一篇:Leetcode47.全排列II


下一篇:1536. 排布二进制网格的最少交换次数