树形图计数——特殊的图逆向搜索法

树形图计数

count.pas/c/cpp

 

【问题描述】

       k同学最近正在研究最小树形图问题。所谓树形图,是指有向图的一棵有根的生成树,其中树的每一条边的指向恰好都是从根指向叶结点的方向。现在小k在纸上画了一个图,他想让你帮忙数一下这个图有多少棵树形图。

 

【输入格式】

1行输入1个正整数:n,表示图中点的个数

2~n+1行每行输入n个字符,描述了这个图的邻接矩阵。第i+1行第j个字符如果是0则表示没有从i连向j的有向边,1表示有一条从ij的有向边。

 

【输出格式】

输出11个整数,表示这个有向图的树形图个数。

 

【样例输入】

count.in

4

0100

0010

0001

1000

 

【样例输出】

count.out

4

 

【数据规模和约定】

对于100%的数据, n<=8

 

统计树形图即统计生成树的个数

以下的方法是用枚举+逆向搜索实现的

具体的解释在代码中

 1 program count;
2 var
3 a,b:array[1..10,1..10]of longint;
4 f,ff:array[1..10]of boolean;
5 fa:array[1..10]of longint;
6 n,i,j,k,root:longint;
7 ans:qword;
8 flag:boolean;
9 ch:char;
10 function judge:boolean;//判断是否构成了一棵生成树
11 var
12 i,x:longint;
13 begin
14 fillchar(f,sizeof(f),false);
15 f[root]:=true;//根标记为已访问
16 for i:=1 to n do//枚举每个节点向上找
17 begin
18 fillchar(ff,sizeof(ff),false);//ff数组标记用,判断是否有环
19 x:=fa[i];//x为i点的父节点
20 while (fa[x]<>root)and(not f[fa[x]])and(fa[x]<>0) do//当x的父节点不是根,且x父节点未被访问过,且存在x的父节点
21 begin
22 if ff[x] then exit(false);//如果x节点在本次寻找中已被访问,则存在环,返回假
23 ff[x]:=true;//标记x已访问
24 x:=fa[x];//把x赋值为x的父节点编号
25 end;
26 if fa[x]=0 then exit(false);//如果最终x的父节点为0,代表i点未能连到根节点,返回假
27 if (fa[x]=root)or(f[fa[x]]) then//如果x父节点为根节点或x父节点被(大循环中)访问过
28 begin
29 x:=i;//x重新赋值为i
30 while not f[x] do
31 begin
32 f[x]:=true;
33 x:=fa[x];
34 end;//向上追溯并把沿途的点标记为已访问
35 end;
36 end;
37 exit(true);//若能执行到这步,返回真
38 end;
39
40 procedure dfs(x:longint);//搜索x节点,按顺序搜——1~n,枚举每个节点的父节点
41 var
42 i,j:longint;
43 begin
44 if x=root then
45 begin
46 dfs(x+1);
47 exit;//如果正在搜根,则跳过
48 end;
49 if x=n+1 then
50 begin
51 if judge then inc(ans);
52 exit;
53 end;//如果已经搜完了所有的点,则判断是否符合题意,若符合,则answer加一
54 for i:=1 to n do
55 if b[i,x]<>0 then
56 begin
57 fa[x]:=i;
58 dfs(x+1);
59 end;//再如果是别的情况(不是根节点,且正在访问图中的节点),则枚举每个节点,看是否有i——>x的边
60 //若有边,则把x的父节点暂定为i,搜索下一个点(这样也很好地处理了不同树形的情况)
61 //因为回溯回来时会对该点可能的入边接着进行枚举
62 end;
63
64 begin
65 assign(input,'count.in');
66 reset(input);
67 assign(output,'count.out');
68 rewrite(output);
69 readln(n);
70 for i:=1 to n do
71 begin
72 for j:=1 to n do
73 begin
74 read(ch);
75 if ch='1' then b[i,j]:=1
76 else b[i,j]:=0;
77 end;
78 readln;
79 end;//读入邻接矩阵并存储
80 for root:=1 to n do//枚举根节点
81 begin
82 flag:=false;
83 for i:=1 to n do
84 if b[root,i]<>0 then
85 begin
86 flag:=true;
87 break;
88 end;//如果flag为true,说明有连出去的边,即,root点可以做根,为下面的搜索作判断根据
89 fa[root]:=root;//父亲数组记录此节点的父节点
90 if flag then dfs(1);//若root可做根,则搜索
91 end;
92 writeln(ans);
93 close(input);
94 close(output);
95 end.


posted on 2011-10-15 12:18  codeway3  阅读(812)  评论(1编辑  收藏  举报

导航