Gym 101873D - Pants On Fire - [warshall算法求传递闭包]
题目链接:http://codeforces.com/gym/101873/problem/D
题意:
给出 $n$ 个事实,表述为 "XXX are worse than YYY"。再给出 $m$ 个某人说的话,也是表述为 "XXX are worse than YYY",对于每句话都要判断是否正确:
如果正确,输出 "Fact";如果错误,输出 "Alternative Fact";如果无法判断,输出 "Pants on Fire"。
题解:
本题是求传递闭包。
关于传递闭包,例如有 $A=\{0,1,2\}$,基于 $A$ 的关系集合 $R=\{<0,0>,<1,0>,<2,2>,<1,2>,<2,1>\}$,
而 $R$ 的传递闭包 $t(R) = \{<0,0>,<1,0>,<2,2>,<2,1>,<1,2>,<1,1>,<2,0>\}$。
学过离散数学都知道,可以用warshall算法求传递闭包:
首先用邻接矩阵 $A$ 表示关系。
(1)置新矩阵 $A=M$;
(2)令 $j=1$;
(3)对所有 $i$ 如果 $A[i,j] = 1$,则对 $k = 1,2,\cdots,n$,$A[i,k] = A[i,k] or A[j,k]$;
(4)$j+=1$(i是行,j是列);
(5)如果 $j \le n$,则转到步骤(3),否则算法结束。
for(int j=1;j<=tot;j++) { for(int i=1;i<=tot;i++) { if(!edge[i][j]) continue; for(int k=1;k<=tot;k++) { edge[i][k]|=edge[j][k]; } } }
观察一下上述代码,可改成:
for(int j=1;j<=tot;j++) { for(int i=1;i<=tot;i++) { for(int k=1;k<=tot;k++) { edge[i][k]|=edge[i][j]&edge[j][k]; } } }
然后你就会发现,warshall算法和floyd算法异曲同工,然后你就会发现floyd算法全名是floyd-warshall算法。(QWQ)
AC代码:
#include<bits/stdc++.h> using namespace std; const int maxn=400+10; int n,m; int edge[maxn][maxn]; int tot; map<string,int> mp; int main() { cin>>n>>m; tot=0; mp.clear(); memset(edge,0,sizeof(edge)); for(int i=1,u,v;i<=n;i++) { string s; cin>>s; if(mp.count(s)) u=mp[s]; else u=mp[s]=++tot; cin>>s; cin>>s; cin>>s; cin>>s; if(mp.count(s)) v=mp[s]; else v=mp[s]=++tot; edge[u][v]=1; } for(int j=1;j<=tot;j++) { for(int i=1;i<=tot;i++) { for(int k=1;k<=tot;k++) { edge[i][k]|=edge[i][j]&edge[j][k]; } } } for(int i=1,u,v;i<=m;i++) { string s; cin>>s; u=mp[s]; cin>>s; cin>>s; cin>>s; cin>>s; v=mp[s]; if(edge[u][v]) printf("Fact\n"); else if(edge[v][u]) printf("Alternative Fact\n"); else printf("Pants on Fire\n"); } }
转载请注明出处:https://dilthey.cnblogs.com/