和吴昊一起玩推理 Round 7 —— 推理逻辑中的传递闭包(HDOJ 1704)

 

如图所示,此为哲学家亚里士多德,以下给出他的三段论——三段论 (syllogism)是传统逻辑中的一类主要推理。又称直言三段论。古希腊哲学家亚里士多德首先提出了关于三段论的系统理论。形式逻辑间接推理的基本形式之一,由大前提小前提推出结论。如‘凡金属都能导电’(大前提),‘铜是金属’(小前提),‘所以铜能导电’(结论)。这称为三段论法或三段论式。三段论属于一种演绎逻辑,是不同于归纳逻辑的,具有较强的说服力。

  当然,三段论的使用是有一定条件的,比如,就两场比赛而言,A赢了B,B赢了C,不能由此得到A赢了C,毕竟,A和C之间还没有比过。但是,在数字之间是可以进行这样的比较的没有错。比如,A比B多3,B比C多4,那么,至少是A比C要多没有错。

 (HDOJ 1704)有n个人和m场比赛,输出在这n个人中有多少场的比赛是不能确定的,并规定了

  if A wins B, and B wins C, then A wins C. ask A B, and ask B A is the same;

  求对于一个特定的TEAM来说,每场比赛结束之后,还有多少场“可能”的“预测比赛”是胜负未定的?

  对于传递闭包来说,其时间复杂度O(n^3),只要500个数据量就会超时1S(这里还不包括样例的数目),这也就是传递闭包的缺陷吧,不过,使用起来还是相当方便的,这里给出Source,以及传递闭包的具体应用(我这里会加粗显示出来的)

 

 1  #include <stdio.h>
 2  #include < string.h>
 3 
 4   int s[ 601][ 601];  // 为传递闭包准备的二维数组
 5 
 6   int main( )
 7  {
 8     int p,q,n,m,t;
 9     int count ;
10     int i , j , k , c ;
11    scanf(  " %d " , &t ) ;
12     while( t -- )
13    {
14      memset( s ,  0 ,  sizeof( s ) ) ;
15      scanf(  " %d %d " , &n , &m ) ;
16      n++ ;
17      top =  1 ;
18       for( c =  0 ; c < m ; c ++ )
19      {
20        scanf(  " %d %d " , &i , &j ) ;
21         // 第i人可以胜过第j人
22         s[i][j] =  1 ;
23        s[j][i] = - 1 ;
24      }
25      count =  0 ;
26 
27       // 闭包处理的整个过程
28        for( k =  1 ; k < n ; k ++ )
29      {
30         for( i =  1 ; i < n ; i ++ )
31        {
32           if( s[i][k] >  0 )
33           for( j =  1 ; j < n ; j ++ )
34          {
35             if( s[k][j] >  0 )
36            {
37              s[i][j] =  1 ; s[j][i] = - 1 ;
38            }
39          }
40        }
41      }
42       for( i =  1 ; i < n ; i ++ )
43      {
44         for( j = i+ 1 ; j < n ; j ++ )
45        {
46           // 逐一扫描,对于胜负未分的情况
47            if( !s[i][j] )
48            count ++ ;
49        }
50      }
51      printf(  " %d\n " , count ) ;
52    }
53     return  0 ;
54  }

 

 

你可能感兴趣的:(round)