Floyd求传递闭包,最小环

https://www.acwing.com/problem/content/345/

acwing 343.排序

Floyd求传递闭包。可以将$A<B$建图为$g[a][b] = 1$。对只有数值$0$和$1$的邻接矩阵跑$Floyd$。

判断的条件有三个:

①当$g[i][j]$ 和 $g[j][i]$都为$0$, 那么就无法确定序列。

②当$g[i][i] = 1$说明有矛盾。

③除以上两种情况外,可以确定序列。

因为每加一条边都要在图上跑一遍$Floyd$所以需要一个数组$d$,每次将$g$复制到$d$,在$d$上跑。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 
 7 const int N = 26;
 8 
 9 int g[N][N], d[N][N];
10 int st[N];
11 int n, m;
12 
13 
14 void Floyd()
15 {
16     memcpy(d, g, sizeof g);
17     for(int k = 0 ; k < n ; k ++)
18         for(int i = 0 ; i < n ; i ++)
19             for(int j = 0 ; j < n ; j ++)
20                 d[i][j] |= d[i][k] && d[k][j];
21 }
22 
23 int check()
24 {
25     for(int i = 0 ; i < n ; i ++)//第二种情况
26         if(d[i][i])return 2;
27         
28     for(int i = 0 ; i < n ; i ++)
29         for(int j = 0 ; j < i ; j ++)
30             if(!d[i][j] && !d[j][i])return 0;//第一种情况,由于对称性,j只需要枚举到i - 1
31     return 1;//第三种情况
32 }
33 
34 
35 int get_min()
36 {
37     for(int i = 0 ; i < n ; i ++)
38         if(!st[i])
39         {
40             bool flag = true;
41             for(int j = 0 ; j < n ; j ++)
42                 if(!st[j] && d[j][i])//在i这个数前面的未被选用的数存在,那么i就不是最小
43                 {
44                     flag = false;
45                     break;
46                 }
47             if(flag)//i是最小,就标记,输出
48             {
49                 st[i] = true;
50                 return 'A' + i;
51             }
52         }
53 }
54 
55 int main(){
56     while(cin >> n >> m, n || m)
57     {
58         memset(g, 0, sizeof g);
59         int type = 0, t;
60         for(int i = 1 ; i <= m ; i ++)
61         {
62             char str[5];
63             
64             cin >> str;
65             
66             int a = str[0] - 'A', b = str[2] - 'A';
67             
68             if(!type)
69             {
70                 g[a][b] = 1;
71                 Floyd();
72                 type = check();
73                 if(type)t = i;
74             }
75             
76         }
77         
78         if(!type)puts("Sorted sequence cannot be determined.");
79         else if(type == 2)printf("Inconsistency found after %d relations.\n", t);
80         else
81         {
82             memset(st, 0, sizeof st);
83             printf("Sorted sequence determined after %d relations: ", t);
84             for(int i = 0 ; i < n ; i ++)printf("%c", get_min());
85             printf(".\n");
86         }
87     }
88     return 0;
89 }

 也可以根据传递的性质,将其优化掉一维的循环。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 
 7 const int N = 30;
 8 int d[N][N];
 9 bool st[N];
10 int n, m;
11 
12 
13 int check()
14 {
15     for(int i = 0 ; i < n ; i ++)
16         if(d[i][i])return 2;//矛盾
17     for(int i = 0 ; i < n ; i ++)
18         for(int j = 0 ; j < i ; j ++)
19             if(!d[i][j] && !d[j][i])
20                 return 0;//不确定
21     return 1;
22 }
23 
24 int get_min()
25 {
26     for(int i = 0 ; i < n ; i ++)
27         if(!st[i])
28         {
29             bool flag = true;
30             for(int j = 0 ; j < n ; j ++)
31                 if(!st[j] && d[j][i])
32                 {
33                     flag = false;
34                     break;
35                 }
36             if(flag)
37             {
38                 st[i] = true;
39                 return 'A' + i;
40             }
41         }
42 }
43 
44 int main(){
45     while(cin >> n >> m, n || m)
46     {
47        
48         int type = 0, t;
49         memset(d, 0, sizeof d);
50         for(int i = 1 ; i <= m ; i ++)
51         { 
52             char str[5];
53             cin >> str;
54             int a = str[0] - 'A', b = str[2] - 'A';
55             if(!type)
56             {
57                 d[a][b] = 1;
58                 for(int x = 0 ; x < n ; x ++)
59                 {
60                     if(d[x][a])d[x][b] = 1;
61                     if(d[b][x])d[a][x] = 1;
62                     for(int y = 0 ; y < n ; y ++)
63                     {
64                         if(d[x][a] && d[b][y])
65                             d[x][y] = 1;
66                     }
67                 }
68                 type = check();
69                 if(type)t = i;
70             }
71         }
72         if(!type)puts("Sorted sequence cannot be determined.");
73         else if(type == 2)printf("Inconsistency found after %d relations.\n", t);
74         else
75         {
76             memset(st, 0, sizeof st);
77             printf("Sorted sequence determined after %d relations: ", t);
78             for(int i = 0 ; i < n ; i ++)printf("%c", get_min());
79             printf(".\n");
80         }
81     }
82     return 0;
83 }

 

 

无向图的最小环。

https://www.acwing.com/problem/content/346/

acwing 344.观光之旅

当外层循环$k$刚开始的时候,$d[i][j]$保存着经过编号不超过$k - 1$的节点,从$i$到$j$的最短路长度。因此,对于经过编号不超过$k$的节点,从i到j的最小环长度就是$d[i][j] + a[i][k] + a[k][j]$。

关于路径的存储。$Floyd$算法的路径更新的条件为$d[i][j] >= d[i][k] + d[k][j]$。如果$d[i][j]$能转移过来,那么说明$d[i][j] = d[i][k] + d[k][j]$。中间点是$k$。这样就由$k$为分界点,将点分为了$0-k$,$k-n$的两段,递归到这两段中,可以继续求得转移的路径。并且转移的状态都是不重复的。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 
 7 const int N = 110, M = 20010;
 8 int d[N][N],g[N][N];
 9 int pos[N][N],path[N];
10 int cnt;
11 
12 void get_path(int i, int j)
13 {
14     if(pos[i][j] == 0)return ;
15     
16     int k = pos[i][j];
17     get_path(i, k);
18     path[cnt ++] = k;
19     get_path(k, j);
20 }
21 
22 int main(){
23     int n, m;
24     cin >> n >> m;
25     
26     memset(g, 0x3f, sizeof g);
27     for(int i = 1 ; i <= n ; i ++)g[i][i] = 0;
28     
29     while(m --)
30     {
31         int a, b, c;
32         cin >> a >> b >> c;
33         g[a][b] = g[b][a] = min(g[a][b], c);
34     }
35     
36     int res = 0x3f3f3f3f;
37     memcpy(d, g, sizeof d);
38     for(int k = 1 ; k <= n ; k ++)
39     {
40         for(int i = 1 ; i < k ; i ++)
41             for(int j = i + 1 ; j < k ; j ++)
42                 if((long long)d[i][j] + g[i][k] + g[k][j] < res)
43                 {
44                     res = d[i][j] + g[i][k] + g[k][j];
45                     cnt = 0;
46                     path[cnt ++] = k;
47                     path[cnt ++] = i;
48                     get_path(i, j);
49                     path[cnt ++] = j;//对于环,逆时针,点依次是k, i, i~j之间的点(递归求得), j
50                 }
51         for(int i = 1 ; i <= n ; i ++)
52             for(int j = 1 ; j <= n ; j ++)
53             {
54                 if(d[i][j] > d[i][k] + d[k][j])
55                 {
56                     d[i][j] = d[i][k] + d[k][j];
57                     pos[i][j] = k;
58                 }
59             }
60     }
61     
62     if(res == 0x3f3f3f3f)puts("No solution.");
63     else for(int i = 0 ; i < cnt ; i ++)cout << path[i] << ' ';
64     
65     return 0;
66 }

 

posted @ 2020-03-22 15:53  dzcixy  阅读(145)  评论(0)    收藏  举报