【树哈希】【状压dp】树

【题目描述】
给出一棵N个节点的树A以及一棵M个节点的树B,求A有多少个不同的连通子图与B同构,答案对109+7取模。

我们定义两个图同构当且仅当存在一个节点的对应方案使得每个图中的每个节点恰好与另一个图中的某个节点相对应,且如果在一个图中两个节点之间有连边,它们在另一个图中对应的两个节点之间也有连边。

【输入】
第一行一个正整数N。

接下来N-1行每行两个整数,表示树中一条边的两端点编号,节点编号为1到N。

接下来一行一个正整数M

接下来M-1行每行两个整数,表示树B中一条边的两端点编号,节点编号为1到M。

【输出】
输出一个非负整数表示答案。

【样例输入】
4
1 2
1 3
1 4
2
1 2
【样例输出】
3
【提示】
对于10%的数据,n,m≤5。

对于30%的数据,n≤20。

对于70%的数据,n≤200。

对于100%的数据,n≤2000,m≤12。

【思路】

这道题也挺好的,听说是【ZJOI2018】线图的一个部分。看到m很小时,是否有一种乱搞的欲望。是的,这道题的做法很玄学,时间复杂度为 O ( 能 过 ) O(能过) O()。为了方便,我们把点数为n的树叫做A,点数为m的叫做B。
1.找重心
首先,为了防止重复,匹配时我们用B的重心尝试与A中每一个点进行匹配。如果B有两个重心,那么我们就枚举A的每一条边与之匹配。为了方便得到这两个重心子树的类型,我们可以新建一个节点当这两个重心的父亲。然后树hash时这两个重心的子树种类也就可以一并得到了。
2.树hash
这里我们通过树hash,要把B中每个子树的情况处理出来,即这个节点有多少个儿子,每个儿子的子树情况又是怎么样的。这样方便进行状压dp。这一步不是很好表述,大致就是用一个vector vv[n]保存对于第i个种类的树,它的儿子的子树对应的子树种类编号为vv[i][j]。
3.状压dp
这一步中,我们枚举A中每一个点,尝试与B的重心匹配。匹配时,我们考虑状压,0表示当前B中匹配节点的儿子子树尚未匹配,1表示已经匹配。为了避免重复,我们强制规定,对于B节点相同的儿子子树,如果前面的没有匹配,后面的也不能匹配。这样,我们只需要枚举A中匹配节点的子树进行匹配,然后递归匹配即可。细节较多,可参考代码。

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define re register
using namespace std;
const int N=3000+5;
const int mod=1e9+7;
int n,m,a,b,c;
inline int red()
{
    int data=0;int w=1; char ch=0;
    ch=getchar();
    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return data*w;
}
int rtx,rty,siz[N],mx=1e9,t[N],cnt=0;
tr1::unordered_map<long long,int>mp;
vector<int>h[N],H1[20],H2[20],v[N],vv[N];
inline void add1(int u,int v){h[u].push_back(v);h[v].push_back(u);}
inline void add2(int u,int v){H1[u].push_back(v);H1[v].push_back(u);}
inline void add3(int u,int v){H2[u].push_back(v);H2[v].push_back(u);}
void findrt(int u,int fa)
{
	siz[u]=1;int son=0;
	for(int re i=H1[u].size()-1;~i;--i)
		if(H1[u][i]!=fa)findrt(H1[u][i],u),siz[u]+=siz[H1[u][i]],son=max(son,siz[H1[u][i]]);
	if(m-siz[u]>son)son=m-siz[u];
	if(son<mx)mx=son,rtx=u,rty=0;
	else if(son==mx)rty=u;
}
void solve(int u,int fa)
{
	for(int re i=H2[u].size()-1;~i;--i)
		if(H2[u][i]!=fa)
		{
			solve(H2[u][i],u);
			vv[u].push_back(t[H2[u][i]]);
		}
	long long hash=0;
	sort(vv[u].begin(),vv[u].end());
	for(int re i=0;i^vv[u].size();++i)(hash*=14)+=vv[u][i];
	t[u]=mp[hash]?mp[hash]:(v[++cnt]=vv[u],mp[hash]=cnt);
}
int vis[N][N],tot=0,f[N][N];
inline void add(int &a,int b){if((a+=b)>=mod)a-=mod;}
int calc(int x,int fa,int t)
{
	int u=vis[x][fa]?vis[x][fa]:vis[x][fa]=++tot;
	if(f[u][t])return f[u][t]-1;
	int *F=new int[1<<v[t].size()];
	for(int re i=F[0]=1;i<(1<<v[t].size());++i)F[i]=0;
	for(int re i=h[x].size()-1;~i;--i)
		if(fa!=h[x][i])
		{
			for(int re j=1<<v[t].size();j--;)
				for(int re k=0;k<v[t].size();++k)
					if(!(j&(1<<k))&&(!k||(j&(1<<k-1))||v[t][k]!=v[t][k-1]))
						add(F[j|(1<<k)],1ll*F[j]*calc(h[x][i],x,v[t][k])%mod);
		}
	f[u][t]=F[(1<<v[t].size())-1]+1;delete F;
	return f[u][t]-1;
}
int ans=0;
int main()
{
	n=red();
	for(int re i=1;i^n;i++)add1(red(),red());
	m=red();
	for(int re i=1;i^m;i++)add2(red(),red());
	findrt(1,0);
	if(rty)
	{
		if(rtx>rty)swap(rtx,rty);
		for(int re i=1;i<=m;i++)
			for(int re j=H1[i].size()-1;~j;--j)
				if(i<H1[i][j]&&(i!=rtx||H1[i][j]!=rty))
					add3(i,H1[i][j]);
		add3(rtx,++m);add3(rty,rtx=m);
	}
	else for(int re i=1;i<=m;i++)H2[i]=H1[i];
	solve(rtx,0);
	if(rty)
	{
		for(int re i=1;i<=n;i++)
			for(int re j=h[i].size()-1;~j;--j)
				if(i<h[i][j])
				{
					add(ans,1ll*calc(i,h[i][j],v[t[m]][0])*calc(h[i][j],i,v[t[m]][1])%mod);
					if(v[t[m]][1]!=v[t[m]][0])add(ans,1ll*calc(i,h[i][j],v[t[m]][1])*calc(h[i][j],i,v[t[m]][0])%mod);
				}
	}
	else for(int re i=1;i<=n;i++)add(ans,calc(i,0,t[rtx]));
	cout<<ans<<"\n";
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蛋白质是生物体中普遍存在的一类重要生物大分子,由天然氨基酸通过肽键连接而成。它具有复杂的分子结构和特定的生物功能,是表达生物遗传性状的一类主要物质。 蛋白质的结构可分为四级:一级结构是组成蛋白质多肽链的线性氨基酸序列;二级结构是依靠不同氨基酸之间的C=O和N-H基团间的氢键形成的稳定结构,主要为α螺旋和β折叠;三级结构是通过多个二级结构元素在三维空间的排列所形成的一个蛋白质分子的三维结构;四级结构用于描述由不同多肽链(亚基)间相互作用形成具有功能的蛋白质复合物分子。 蛋白质在生物体内具有多种功能,包括提供能量、维持电解质平衡、信息交流、构成人的身体以及免疫等。例如,蛋白质分解可以为人体提供能量,每克蛋白质能产生4千卡的热能;血液里的蛋白质能帮助维持体内的酸碱平衡和血液的渗透压;蛋白质是组成人体器官组织的重要物质,可以修复受损的器官功能,以及维持细胞的生长和更新;蛋白质也是构成多种生理活性的物质,如免疫球蛋白,具有维持机体正常免疫功能的作用。 蛋白质的合成是指生物按照从脱氧核糖核酸(DNA)转录得到的信使核糖核酸(mRNA)上的遗传信息合成蛋白质的过程。这个过程包括氨基酸的活化、多肽链合成的起始、肽链的延长、肽链的终止和释放以及蛋白质合成后的加工修饰等步骤。 蛋白质降解是指食物中的蛋白质经过蛋白质降解酶的作用降解为多肽和氨基酸然后被人体吸收的过程。这个过程在细胞的生理活动中发挥着极其重要的作用,例如将蛋白质降解后成为小分子的氨基酸,并被循环利用;处理错误折叠的蛋白质以及多余组分,使之降解,以防机体产生错误应答。 总的来说,蛋白质是生物体内不可或缺的一类重要物质,对于维持生物体的正常生理功能具有至关重要的作用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值