POI2000 迷宫的墙

题意描述

迷宫的墙

给出一棵有 \(n-1\) 个节点树,每个节点都有一种颜色,一共只有三种颜色,每个非叶子节点的出度为 \(3\)

每个节点都指向编号比自己大的节点

树以 \(1\) 号节点为根,树的所有叶子节点都指向节点 \(n\),而且每个节点的三条边是有顺序的,编号为 \(1,2,3\)

针对每一条 \(1\to n\) 的路径,我们可以用一次遍历的颜色边的编号来代表它,从而得到原树的颜色路径集合

如果树中存在某些节点,删除它们之后 将剩余节点重新连边 发现仍然可以构造出与原来相同的颜色路径集合。

那么它们被认为是可以删除的,求删除之后的树的总结点数。

算法分析

倒序处理+Hash

这道题看上去很不可做,给定条件很多而且复杂,主要问题是思维的转化。

给出方法:一个节点是可删除的,当且仅当树中存在它的等价节点

其中两个节点是等价的,仅当两者颜色相同,两者子节点也是等价的(或相同的),而且子节点排列顺序相同。

证明:

两个节点指向相同或等价节点,表示我完全可以将编号较小的节点删去,

将指向它的边重新指向编号较大的节点,从而完成一次完美的删除。

由于子节点排列顺序相同,且两者颜色相同,所以保证了路径上遍历的颜色边的编号均相同。

值得注意的是,根据定义,如果两个节点是等价的,那么以两者为根的子树形成了一一对应的等价关系。

相当于我们找到了两个同构的子树,显然可以任意删去一个。

代码实现

根据上面的定义,需要判断两个节点是否为等价节点,必须事先判断其子节点。

所以我们采用编号从大到小倒序处理。

对于每个节点,我们将它的子节点与它的颜色组合在一起,进行一次 Hash,存入 map 中。

当出现相同的 Hash 值时,就将当前节点(编号较小)替换为 map 中原有的节点(编号较大)。

具体流程是酱紫的:

  1. \(to(i)\) 表示 \(i\) 节点的等效节点,首先令 \(to(i)=i,ans=n\)
  2. 倒序处理节点,对于每一个节点 \(i\),设其子节点为 \(A,B,C\),其颜色为 \(c(i)\)
  3. \(Hash=c(i)\times n^3+to(A)\times n^2+to(B)\times n+to(C)\)。(可以证明不存在 Hash 冲突)
  4. 如果 \(mp(Hash)=j\),则令 \(to(i)=j,ans--\)
  5. 否则令 \(mp(Hash)=i\)
  6. 重复执行 \(2\to 5\),直至结束,当前的 \(ans\) 即为答案。
#include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 6010
using namespace std;

int n;
int c[N],to[N];
int a[N][5];
map<long long,int>mp;

int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
	while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
	return x*f;
}

int main(){
    //freopen("lab.in","r",stdin);
    //freopen("lab.out","w",stdout);
    n=read();
    char s[2];
    for(int i=1;i<n;i++){
        scanf("%s",s);
        if(s[0]=='N') c[i]=1;
        else if(s[0]=='Z') c[i]=2;
        else c[i]=3;
        for(int j=1;j<=3;j++) a[i][j]=read();
    }
    for(int i=1;i<=n+1;i++) to[i]=i;
    int ans=n;
    for(int i=n-1;i>=1;i--){
        long long now=c[i];
        for(int j=1;j<=3;j++) a[i][j]=to[a[i][j]];
        for(int j=1;j<=3;j++) now=now*n+a[i][j];
        if(mp.find(now)==mp.end()) mp[now]=i;
        else{ans--;to[i]=mp[now];}
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2021-02-25 21:08  LPF'sBlog  阅读(73)  评论(0编辑  收藏  举报