來源: APCS 2024/01 第三題
這題的解法有很多種,像是拓樸排序 BFS… 這邊就來講一下另一種解法: DFS+DP
雖然不是最快的寫法但也值得大家學習,好處是寫法比較直覺,也比較好debug(? 好像也沒有XD
直接從圖上應該就能看出他的遞迴關係式,於是我們從輸出端一直往回找直到找到根結點再慢慢推回去,推回去的過程中我們把這些節點都存起來,下次遇到時就可以直接拿來用 (有一點 Top-Down DP的感覺)
程式碼如下:
#include <bits/stdc++.h>
using namespace std;
int p, q, r, m;
vector<int> el; // 儲存輸入節點的狀態與邏輯閘類型
vector<bool> vis;
vector<vector<int>> mp;
vector<pair<int, int>> dp;
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> p >> q >> r >> m;
el.assign(p+q+1, 0);
mp.assign(p+q+r+1, {});
vis.assign(p+q+r+1, 0);
dp.resize(p+q+r+1);
for (int i = 1; i <= p+q; i++)
cin >> el[i];
int a, b;
while (m--){
cin >> a >> b;
mp[b].push_back(a);
}
程式碼如下:
// 狀態, 邏輯閘數 (delay)
pair<int, int> dfs(int idx){
if (idx <= p){ // 判斷是否為輸入節點
vis[idx] = 1;
return dp[idx] = {el[idx], 0};
}
if (idx > p+q && idx <= p+q+r) // 判斷是否為輸出節點
return dfs(mp[idx][0]); // 輸入節點不可能找過所以直接下去搜就好
if (vis[idx])
return dp[idx]; // 如果找過了就直接回傳
vis[idx] = 1;
auto x = dfs(mp[idx][0]); // 搜尋第一個子節點
if (el[idx] == 4) //Not 只有一個輸入所以要先判斷
return dp[idx] = {!x.first, x.second+1};
auto y = dfs(mp[idx][1]); // 如果不是 Not 閘的話就再找一個輸入
if (el[idx] == 1)
return dp[idx] = {(x.first && y.first), max(x.second, y.second)+1};
if (el[idx] == 2)
return dp[idx] = {(x.first || y.first), max(x.second, y.second)+1};
if (el[idx] == 3)
return dp[idx] = {(x.first ^ y.first), max(x.second, y.second)+1}; // x.first ^ y.first 等價於 (!x.first && y.first) || (x.first && !y.first)
}
程式碼如下:
int delay = INT_MIN;
vector<int> ans;
for (int i = p+q+1; i <= p+q+r; i++){
auto d = dfs(i);
ans.push_back(d.first);
delay = max(delay, d.second);
}
cout << delay << '\n';
for (auto i: ans)
cout << i << ' ';
#include <bits/stdc++.h>
using namespace std;
int p, q, r, m;
vector<int> el;
vector<bool> vis;
vector<vector<int>> mp;
vector<pair<int, int>> dp;
pair<int, int> dfs(int idx){
if (idx <= p){
vis[idx] = 1;
return dp[idx] = {el[idx], 0};
}
if (idx > p+q && idx <= p+q+r)
return dfs(mp[idx][0]);
if (vis[idx])
return dp[idx];
vis[idx] = 1;
auto x = dfs(mp[idx][0]);
if (el[idx] == 4)
return dp[idx] = {!x.first, x.second+1};
auto y = dfs(mp[idx][1]);
if (el[idx] == 1)
return dp[idx] = {(x.first && y.first), max(x.second, y.second)+1};
if (el[idx] == 2)
return dp[idx] = {(x.first || y.first), max(x.second, y.second)+1};
if (el[idx] == 3)
return dp[idx] = {(x.first ^ y.first), max(x.second, y.second)+1};
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> p >> q >> r >> m;
el.assign(p+q+1, 0);
mp.assign(p+q+r+1, {});
vis.assign(p+q+r+1, 0);
dp.resize(p+q+r+1);
for (int i = 1; i <= p+q; i++)
cin >> el[i];
int a, b;
while (m--){
cin >> a >> b;
mp[b].push_back(a);
}
int delay = INT_MIN;
vector<int> ans;
for (int i = p+q+1; i <= p+q+r; i++){
auto d = dfs(i);
ans.push_back(d.first);
delay = max(delay, d.second);
}
cout << delay << '\n';
for (auto i: ans)
cout << i << ' ';
}
如果內容有誤還麻煩敲我 ><
Learn More →
關於我
Mar 5, 2025-> 解題思路:// 將分數>=60 設為 x 而<60 設為 y// 並將其排序 x 找出最小值 y 找出最大值// 如果x沒有元素 代表沒有最小的及格成績 即為 wrost case// 如果y沒有元素 代表沒有最大的不及格成績 即為 best case
Jun 29, 2024#include <bits/stdc++.h>#define Youtong ios::sync_with_stdio(0); cin.tie(0)#define pii pair<int, string>using namespace std;
May 18, 2024來源: APCS 2022/10 #dfs #tree
Mar 3, 2024or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up