題目
下圖轉自“英式沒品笑話百科”的新浪微博 —— 所以無論有沒有遇到難題,其實都不用擔心。
博主將這種邏輯推演稱為“邏輯自洽”,即從某個命題出發的所有推理路徑都會將結論引導到同一個最終命題(開玩笑的,千萬別以為這是真正的邏輯自洽的定義……)。現給定一個更為復雜的邏輯推理圖,本題就請你檢查從一個給定命題到另一個命題的推理是否是“邏輯自洽”的,以及存在多少種不同的推理路徑。例如上圖,從“你遇到難題了嗎?”到“那就別擔心了”就是一種“邏輯自洽”的推理,一共有 3 條不同的推理路徑。
輸入格式:
輸入首先在一行中給出兩個正整數 N(1<N≤500)和 M,分別為命題個數和推理個數。這里我們假設命題從 1 到 N 編號。
接下來 M 行,每行給出一對命題之間的推理關系,即兩個命題的編號 S1 S2
,表示可以從 S1
推出 S2
。題目保證任意兩命題之間只存在最多一種推理關系,且任一命題不能循環自證(即從該命題出發推出該命題自己)。
最后一行給出待檢驗的兩個命題的編號 A B
。
輸出格式:
在一行中首先輸出從 A
到 B
有多少種不同的推理路徑,然后輸出 Yes
如果推理是“邏輯自洽”的,或 No
如果不是。
題目保證輸出數據不超過 109。
思路
記憶搜索以后bfs遍歷一遍標記
#include<bits/stdc++.h>
using namespace std;
//#define int long long
vector<int>edge[510];
int s, t;
int dp[510];
int dfs(int u) {
if (dp[u]) {
return dp[u];
}
if (u == t) {
return 1;
}
for (auto v : edge[u]) {
dp[u] += dfs(v);
}
return dp[u];
}
int flag;
int vis[510];
void bfs1() {
queue<int>Q;
Q.push(s);
while (!Q.empty()) {
int now = Q.front(); Q.pop();
if (vis[now]) continue;
vis[now] = 1;
if (!dp[now]) {
flag = 1; break;
}
if (now == t) continue;
for (auto v : edge[now]) {
Q.push(v);
}
}
}
signed main() {
int n, m;
cin >> n >> m;
while (m--) {
int u, v;
cin >> u >> v;
edge[u].push_back(v);
}
cin >> s >> t;
dfs(s);
cout << dp[s] -dp[t] << " ";
dp[t] = 1;
bfs1();
if (!flag) cout << "Yes\n";
else cout << "No\n";
}
/*
1 2
1 3
1 4
2 5
3 5
4 5
5 6
5 7
5 8
6 7
6 9
7 9
8 9
*/