【题目来源】
https://pintia.cn/problem-sets/994805046380707840/exam/problems/type/7?page=1&problemSetProblemId=1336215880692482060
【题目描述】
下图转自“英式没品笑话百科”的新浪微博 —— 所以无论有没有遇到难题,其实都不用担心。
博主将这种逻辑推演称为“逻辑自洽”,即从某个命题出发的所有推理路径都会将结论引导到同一个最终命题(开玩笑的,千万别以为这是真正的逻辑自洽的定义……)。现给定一个更为复杂的逻辑推理图,本题就请你检查从一个给定命题到另一个命题的推理是否是“逻辑自洽”的,以及存在多少种不同的推理路径。例如上图,从“你遇到难题了吗?”到“那就别担心了”就是一种“逻辑自洽”的推理,一共有 3 条不同的推理路径。
【输入格式】
输入首先在一行中给出两个正整数 N(1<N≤500)和 M,分别为命题个数和推理个数。这里我们假设命题从 1 到 N 编号。
接下来 M 行,每行给出一对命题之间的推理关系,即两个命题的编号 S1 S2,表示可以从 S1 推出 S2。题目保证任意两命题之间只存在最多一种推理关系,且任一命题不能循环自证(即从该命题出发推出该命题自己)。
最后一行给出待检验的两个命题的编号 A B。
【输出格式】
在一行中首先输出从 A 到 B 有多少种不同的推理路径,然后输出 Yes 如果推理是“逻辑自洽”的,或 No 如果不是。
题目保证输出数据不超过 10^9。
【输入样例1】
7 8
7 6
7 4
6 5
4 1
5 2
5 3
2 1
3 1
7 1
【输出样例1】
3 Yes
【输入样例2】
7 8
7 6
7 4
6 5
4 1
5 2
5 3
6 1
3 1
7 1
【输出样例2】
3 No
【算法分析】
● 深度优先搜索(DFS)代码的具象化 → 探险家与迷宫:https://blog.csdn.net/hnjzsyjyj/article/details/147073418
● dfs算法模板:https://blog.csdn.net/hnjzsyjyj/article/details/118736059
dfs算法常表现为复杂的递归函数形式,因此掌握递归是理解dfs算法的基础。
void dfs(int step) {
判断边界 {
输出解
}
尝试每一种可能 {
满足check条件{
标记
继续下一步:dfs(step+1)
恢复初始状态(回溯的时候要用到)
}
}
}
● yxc 图示“链式前向星”核心操作:https://blog.csdn.net/hnjzsyjyj/article/details/139369904
大佬 yxc 指出“链式前向星”就是“多单链表”,每条单链表基于“头插法”并用 e[]、ne[]、h[] 、val[] 等数组进行模拟创建。其中:
e[idx]:存储序号为 idx 的边的终点值
ne[idx]:存储序号为 idx 的边指向的边的序号(模拟链表指针)
h[a]:存储头结点 a 指向的边的序号
val[idx]:存储序号为 idx 的边的权值(可选)
【算法代码一:链式前向星】
若 N 取 500,会报“段错误”。这是因为,当 N=500 时,图的边数最多可达 N(N+1)/2=125250 条,超过基于 N<<1 得到的结果。基于此,将 N 的值设为 1e5+5,即适当地大,以避免“段错误”。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int h[N],e[N<<1],ne[N<<1],idx;
int st[N],cnt[N];
int n,m,le,ri,sx,ex;
void add(int a,int b) {
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int dfs(int x) {
st[x]=1;
if(cnt[x]) return cnt[x];
for(int i=h[x]; i!=-1; i=ne[i]) {
int j=e[i];
cnt[x]+=dfs(j);
}
return cnt[x];
}
int main () {
memset(h,-1,sizeof h);
cin>>n>>m;
while(m--) {
cin>>le>>ri;
add(le,ri);;
}
cin>>sx>>ex;
cnt[ex]=1;
int ans=dfs(sx);
cout<<ans;
for(int i=1; i<=n; i++) {
if(st[i] && cnt[i]==0) {
cout<<" No";
return 0;
}
}
cout<<" Yes";
return 0;
}
/*
in:
7 8
7 6
7 4
6 5
4 1
5 2
5 3
2 1
3 1
7 1
out:
3 Yes
*/
【算法代码二:邻接表】
#include <bits/stdc++.h>
using namespace std;
const int N=505;
vector<int> v[N];
int st[N],cnt[N];
int n,m,le,ri,sx,ex;
int dfs(int x) {
st[x]=1;
if(cnt[x]) return cnt[x];
for(int i=0; i<v[x].size(); i++) {
cnt[x]+=dfs(v[x][i]);
}
return cnt[x];
}
int main () {
cin>>n>>m;
while(m--) {
cin>>le>>ri;
v[le].push_back(ri);
}
cin>>sx>>ex;
cnt[ex]=1;
int ans=dfs(sx);
cout<<ans;
for(int i=1; i<=n; i++) {
if(st[i] && cnt[i]==0) {
cout<<" No";
return 0;
}
}
cout<<" Yes";
return 0;
}
/*
in:
7 8
7 6
7 4
6 5
4 1
5 2
5 3
2 1
3 1
7 1
out:
3 Yes
*/
【参考文献】
https://www.acwing.com/file_system/file/content/whole/index/content/9033086/
https://tiku.scratchor.com/paper/view/bfs04onsf10vuuzd
https://www.cnblogs.com/abestxun/p/14695265.html
https://blog.csdn.net/qq_35776409/article/details/110930969
https://blog.csdn.net/hnjzsyjyj/article/details/139369904
https://www.cnblogs.com/RioTian/p/14678570.html