解题报告 树形图计数

1.        题目

树形图计数

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 .

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.

 

原文地址:https://www.cnblogs.com/SueMiller/p/2213100.html