1. 题目
树形图计数
count.pas/c/cpp
【问题描述】
小k同学最近正在研究最小树形图问题。所谓树形图,是指有向图的一棵有根的生成树,其中树的每一条边的指向恰好都是从根指向叶结点的方向。现在小k在纸上画了一个图,他想让你帮忙数一下这个图有多少棵树形图。
【输入格式】
第1行输入1个正整数:n,表示图中点的个数
第2~n+1行每行输入n个字符,描述了这个图的邻接矩阵。第i+1行第j个字符如果是0则表示没有从i连向j的有向边,1表示有一条从i到j的有向边。
【输出格式】
输出1行1个整数,表示这个有向图的树形图个数。
【样例输入】
count.in
4
0100
0010
0001
1000
【样例输出】
count.out
4
【数据规模和约定】
对于100%的数据,n<=8 .
2. 算法
以每一个节点为根,判断从这个根开始用有向边能不能找到所有节点,如果能则记录。
判断方法:首先将这棵树构建出来,也就是轮流将该点的入度所连的点作为他的父亲节点,看可不可以将这棵树构建出来,如果可以,再看构建出来的树能不能找到所有节点。
3. 注意事项
要先将这棵树构建出来,再判断。
4. 代码
深搜+判断(ASDF)
program asdf;
var
b,a:array[0..10,0..10]of longint;
f,ff:array[0..10]of boolean;
fa:array[0..10]of longint;
n,i,j,k,root:longint;
all,sum,ans:qword;
flag:boolean;
ch:char;
function judge:boolean;
var
i,x:longint;
begin
fillchar(f,sizeof(f),false);
f[root]:=true;
for i:=1 to n do
begin
fillchar(ff,sizeof(ff),false);
x:=fa[i];
while (fa[x]<>root)and(not f[fa[x]])and(fa[x]<>0) do
begin
if ff[x] then exit(false);
ff[x]:=true;
x:=fa[x];
end;
if fa[x]=0 then exit(false);
if (fa[x]=root)or(f[fa[x]]) then
begin
x:=i;
while not f[x] do
begin
f[x]:=true;
x:=fa[x];
end;
end;
end;
exit(true);
end;
procedure dfs(x:longint);
var
i:longint;
begin
if x=root then
begin
dfs(x+1);
exit;
end;
if x=n+1 then
begin
if judge then inc(ans);
exit;
end;
for i:=1 to n do
if b[i,x]<>0 then
begin
fa[x]:=i;
dfs(x+1);
end;
end;
begin
assign(input,'count.in');reset(input);
assign(output,'count.out');rewrite(output);
readln(n);
for i:=1 to n do
begin
for j:=1 to n do
begin
read(ch);
if ch='1' then b[i,j]:=1
else b[i,j]:=0;
end;
readln;
end;
for root:=1 to n do
begin
flag:=false;
for i:=1 to n do
if b[root,i]<>0 then
begin
flag:=true;
break;
end;
fa[root]:=root;
if flag then
dfs(1);
end;
write(ans);
close(input);
close(output);
end.