和吴昊一起玩推理 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 }
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 }