题目大意:
给一棵树上的结点编号,满足:
1、每个结点的子节点编号连续。
2、每个节点下的子树的编号连续。
求总的方案数。
分析:
可以发现每个节点的非叶子儿子结点最多只能有两个,因为如果多于两个,不妨设编号为k+1,k+2,……,k+n,由于要满足条件2,则除了k+n这个结点的子结点可以继续往下编号,其他的结点的子节点都无法再进行编号(无法满足条件2)
对于某个结点,设它的叶子结点个数为a,非叶子结点个数为b。
若b>2,方案数为0
若b=2,此时这两个非叶子结点的编号固定了,方案数取决于叶子结点个数,为a!,即叶子结点个数的全排列。
若b=1,此时该非叶子结点的编号为兄弟结点中最大或者最小,即两种方案,总方案数为2*a!
若b=0,此时该结点的编号可以和叶子结点中的最大或者最小的那个互换,有两种方案,总方案数为2*a!
坑点:n=1的时候,直接输出1
#include<iostream> #include<cstdio> #include<cmath> #include<map> #include<set> #include<algorithm> #include<queue> #include<stack> #include<cstdlib> #include<cstring> #include<vector> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; typedef long long LL; typedef unsigned long long uLL; typedef __int64 LI; typedef unsigned __int64 uLI; typedef unsigned int uI; typedef double db; #define maxn 100005 #define inf 0x3f3f3f3f #define mod 1000000007 struct Edge{ int to,next; }edge[200005]; int head[100005],num[100005],cnt,n; bool vis[100005]; LI A[100005]; inline void add(int u,int v){ edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++; } LI bfs(){ memset(vis,0,sizeof(vis)); vis[1]=1; queue<int> q; q.push(1); LI ans=1; while(!q.empty()){ int a=0,b=0,u=q.front();q.pop(); for(int i=head[u];~i;i=edge[i].next){ int v=edge[i].to; if(vis[v]) continue; vis[v]=1; int num=0; for(int j=head[v];~j;j=edge[j].next){ ++num; if(num>1) break; } if(num>1) {q.push(v);++b;} else ++a; } if(b>2) return 0; else if(b==2) ans=ans*A[a]%mod; else ans=ans*2%mod*A[a]%mod; } return ans; } void init(){ A[0]=A[1]=1; for(int i=2;i<=100000;++i) A[i]=A[i-1]*i%mod; } int main() { int t,i,ca=1,n,a,b; init(); cin>>t; while(t--) { memset(head,-1,sizeof(head)); cnt=0; scanf("%d",&n); for(i=1;i<n;++i){ scanf("%d%d",&a,&b); add(a,b); add(b,a); } printf("Case #%d: %I64d\n",ca++,n==1?1:bfs()); } return 0; }