Vijos 有根树的同构问题字符串---最小表示法
Posted 心之所向 素履以往
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vijos 有根树的同构问题字符串---最小表示法相关的知识,希望对你有一定的参考价值。
背景
经典题
描述
所谓图的同构是指两个图“相同”。图的同构有着广泛的应用,比如当要对一批图施行某种操作的时候,如果能发现其中有一些图是同构的,就可以在这些同构的图中只保留一个,从而降低工作量。例如,图1所示的T1和T3就是同构的。
图的同构的定义:给出两个图G1=(V1,E1),G2=(V2,E2)。如果存在一个V1到V2的一一映射f,使得(x,y)是G1的边,当且仅当(f(x),f(y))是G2的边,则称G1和G2是同构的。也就是说,我们只关心顶点间的拓扑关系而不关心顶点的编号。
任意图的同构的判定尚无有效的算法,但要判断两棵树是否同构则要容易些。下面我们仅考虑有根树(即树形图:有向图,存在一个根,入度为0,从根到其他任一顶点恰好有一条有向路)。给出k棵有根树T1,T2,…,Tk,每棵树都有n个顶点,你的任务是求出这些树在同构关系下的所有等价类(如果两棵树同构,则它们属于同一个等价类)。
格式
输入格式
输入的第1行包含两个整数k(1<=k<=100)和n(1<=n<=50),表示总共有k棵树,每棵都是n个顶点。接下来k行,每行描述一棵树;每行包含n-1对整数,表示这棵树的n-1条有向边;数字间用空格隔开。顶点的编号为1到n,每对整数xy表示存在一条x指向y的有向边。树的编号和在数据中出现的顺序一致,也就是说输入文件中第2行描述的是T1,第3行描述的是T2,……,第k+1行描述的是Tk。
输出格式
把给出的k棵树划分为不同的等价类,使得同一等价类中任意两棵树同构。对于每个等价类,从小到大输出这个等价类中的树的编号,用等号隔开。如果有m个等价类,则按字典序输出,每个一行。例如,有4个等价类{4,2,7},{5,1,3},{8,9},{6},则输出
1=3=5
2=4=7
6
8=9
注意,数字和等号之间不要有空格;行首和行末可以有空格。
样例1
样例输入1
3 7
7 2 7 1 7 6 2 3 1 4 6 5
7 2 7 1 2 3 1 4 1 5 5 6
4 3 3 2 4 1 1 7 5 6 4 5
样例输出1
1=3
2
限制
1s
1 /* 2 把每棵树按拓扑关系转换成括号序列 3 每一种拓扑关系的序列是唯一的 4 只要dfs找到括号序列 5 再判断相等关系就好了 6 */ 7 #include<cstdio> 8 #include<iostream> 9 #include<algorithm> 10 #define MAXN 110 11 using namespace std; 12 13 int n,m,special[MAXN]; 14 15 struct node { 16 int to; 17 int next; 18 }; 19 node e[MAXN*MAXN]; 20 21 int head[MAXN],tot; 22 23 string s[MAXN]; 24 25 inline void read(int&x) { 26 int f=1;x=0;char c=getchar(); 27 while(c>‘9‘||c<‘0‘) {if(c==‘-‘) f=-1;c=getchar();} 28 while(c>=‘0‘&&c<=‘9‘) x=10*x+c-48,c=getchar(); 29 x=x*f; 30 } 31 32 inline void add(int x,int y) { 33 e[++tot].to=y; 34 e[tot].next=head[x]; 35 head[x]=tot; 36 } 37 38 inline bool cmp(string aa,string bb) { 39 int len=aa.length(),len1=bb.length(); 40 if(len==len1) { 41 for(int i=0;i<len;i++) 42 if(aa[i]!=bb[i]) return aa[i]<bb[i]; 43 } 44 return len<len1; 45 } 46 47 inline string dfs(int u) { 48 string bs[MAXN]; 49 int k=1; 50 for(int i=head[u];i;i=e[i].next,k++) 51 bs[k]=dfs(e[i].to); 52 sort(bs+1,bs+1+k,cmp); 53 string t="("; 54 for(int i=1;i<=k;i++) 55 t+=bs[i]; 56 t=t+")"; 57 return t; 58 } 59 60 int main() { 61 int x,y; 62 read(m);read(n); 63 for(int p=1;p<=m;p++) { 64 for(int i=1;i<n;i++) { 65 read(x);read(y); 66 add(x,y); 67 special[y]=1; 68 } 69 for(int i=1;i<=n;i++) { 70 if(!special[i]) { 71 s[p]=dfs(i); 72 break; 73 } 74 } 75 fill(special+1,special+1+n,0); 76 fill(head+1,head+1+n,0); 77 tot=0; 78 } 79 fill(special+1,special+1+n,0); 80 // for(int i=1;i<=m;i++) cout<<s[i]<<endl; 81 for(int i=1;i<=m;i++) { 82 if(special[i]) continue; 83 printf("%d",i); 84 special[i]=1; 85 for(int j=i+1;j<=m;j++) { 86 if(s[i]==s[j]) 87 special[j]=1,printf("=%d",j); 88 } 89 printf("\n"); 90 } 91 return 0; 92 }
以上是关于Vijos 有根树的同构问题字符串---最小表示法的主要内容,如果未能解决你的问题,请参考以下文章