#39003: C++遞迴解法


jamil130011@gmail.com (許恩嘉)

學校 : 不指定學校
編號 : 249076
來源 : [1.174.49.241]
最後登入時間 :
2023-11-09 17:27:49
m933. 3. 邏輯電路 -- 2024年1月APCS | From: [1.174.63.23] | 發表日期 : 2024-01-07 23:10

想要算出各個輸出端口的延遲,就要先得出其前一個端口的延遲。

想要得出輸出端口的狀態,就要先得出其前一個端口的狀態。

把這寫遞迴式就可以了。

 

我的寫法:

先定義一個結構,儲存電閥的各項資訊

struct vr
{
    int in1 = 0;//輸入端口1
    int in2 = 0;//輸入端口2
    short boool = -1;//這個電閥輸出
    short aoxn = 0;//這個邏輯閥的種類,輸入端口與輸出端口不會用到此參數
    int delay = -10;//電閥的延遲
};

//先宣告一下等一下要用到的函式,使用傳參考呼叫,可以直接修改陣列元素。

vr* pfrs = nullptr;//因為懶得將指標作為函式的引數之一,乾脆宣告成全域變數
short check_boool(vr& fr);//檢查電閥的狀態
int check_delay(vr& fr);//檢查電閥的延遲

將各項輸入儲存進vector<vr>中,從索引值1至(p+q+r),陣列第一項(索引值為0)保留不使用。(這樣比較方便存取)

    int p, q, r, m;
    cin >> p >> q >> r >> m;
    vector<vr> frs(p + q + r + 1);
    frs[0].delay = -1;//陣列第一項將是計算延遲時遞迴的終點。
    for (int i = 1; i < p + 1; ++i) {
        cin >> frs[i].boool;
        frs[i].delay = -1;//輸入端口的延遲視為-1
    }
    int u, v;
    for (int i = p + 1; i < p + q + 1; ++i) {
        cin >> frs[i].aoxn;//輸入各個邏輯閥的種類
    }
    for (int i = 0; i < m; ++i) {
        cin >> u >> v;
        if (frs[v].in1 == 0) {
            frs[v].in1 = u;//電閥的輸入端口1
        }
        else {
            frs[v].in2 = u;//電閥的輸入端口2
        }
    }

pfrs = frs.data();//將全域變數pfrs指向vector<vr> frs的第一個元素,以便在函式中使用

準備工作完成,可以開始寫遞迴用的函式喽!

int check_delay(vr& fr)接受一個指向vr結構的參考,並回傳該電閥的延遲

int check_delay(vr& fr) {
    //如果delay成員不是預設值(-1),代表已計算過此電閥的延遲,直接回傳delay就可以了
    if (fr.delay != -10) {
        return fr.delay;
    }
    //否則計算此電閥的延遲,為兩個輸入電閥中的延遲較大者再加一
    fr.delay = max(check_delay(pfrs[fr.in1]), check_delay(pfrs[fr.in2])) + 1;
    return fr.delay;
}

不用擔心只有1個輸入的電閥(輸出端口與NOT 閘),它們的第二的輸入端口指向了vector<vr> frs的第1個元素(索引值0),該元素已保留不使用。

 

short check_boool(vr& fr)接受一個指向vr結構的參考,並回傳該電閥的輸出

short check_boool(vr& fr) {
    //如果boool成員不是 -1 (預設值),代表已計算過此電閥的輸出,直接回傳boool就可以了
    if (fr.boool != -1) {
        return fr.boool;
    }
    //否則根據電閥種類進行遞迴,判斷此電閥的輸出
    switch (fr.aoxn) {
    case 0://輸出端口
        fr.boool = check_boool(pfrs[fr.in1]);
        return fr.boool;
    case 1://AND 閘
        fr.boool = check_boool(pfrs[fr.in1]) and check_boool(pfrs[fr.in2]) ? 1 : 0;
        return fr.boool;
    case 2://OR 閘
        fr.boool = check_boool(pfrs[fr.in1]) or check_boool(pfrs[fr.in2]) ? 1 : 0;
        return fr.boool;
    case 3://XOR 閘
        fr.boool = check_boool(pfrs[fr.in1]) xor check_boool(pfrs[fr.in2]) ? 1 : 0;
        return fr.boool;
    case 4://NOT 閘
        fr.boool = !check_boool(pfrs[fr.in1]) ? 1 : 0;
        return fr.boool;
    }
}

 

回到main()函式,只要針對每個輸出閥呼叫check_delay與check_boool就可以了。

    int Max=0;
    for (int i = p + q + 1; i < p + q + r + 1; ++i) {
        Max = Max > check_delay(frs[i]) ? Max : frs[i].delay;
    }
    cout << Max << '\n';
    for (int i = p + q + 1; i < p + q + r + 1; ++i) {
        cout<<check_boool(frs[i])<<' ';
    }

 
#39004: Re: C++遞迴解法


jamil130011@gmail.com (許恩嘉)

學校 : 不指定學校
編號 : 249076
來源 : [1.174.49.241]
最後登入時間 :
2023-11-09 17:27:49
m933. 3. 邏輯電路 -- 2024年1月APCS | From: [1.174.63.23] | 發表日期 : 2024-01-07 23:15

結果考試時忘記設置frs[0].delay = -1;作為遞迴終點,導致計算延遲的部分整個錯掉了。

 



 
#39005: Re: C++遞迴解法


jamil130011@gmail.com (許恩嘉)

學校 : 不指定學校
編號 : 249076
來源 : [1.174.49.241]
最後登入時間 :
2023-11-09 17:27:49
m933. 3. 邏輯電路 -- 2024年1月APCS | From: [1.174.63.23] | 發表日期 : 2024-01-07 23:15

結果考試時忘記設置frs[0].delay = -1;作為遞迴終點,導致計算延遲的部分整個錯掉了。

 



 
#39006: Re: C++遞迴解法


jamil130011@gmail.com (許恩嘉)

學校 : 不指定學校
編號 : 249076
來源 : [1.174.49.241]
最後登入時間 :
2023-11-09 17:27:49
m933. 3. 邏輯電路 -- 2024年1月APCS | From: [1.174.63.23] | 發表日期 : 2024-01-07 23:15

結果考試時忘記設置frs[0].delay = -1;作為遞迴終點,導致計算延遲的部分整個錯掉了。

 



 
#39007: Re: C++遞迴解法


jamil130011@gmail.com (許恩嘉)

學校 : 不指定學校
編號 : 249076
來源 : [1.174.49.241]
最後登入時間 :
2023-11-09 17:27:49
m933. 3. 邏輯電路 -- 2024年1月APCS | From: [1.174.63.23] | 發表日期 : 2024-01-07 23:15

結果考試時忘記設置frs[0].delay = -1;作為遞迴終點,導致計算延遲的部分整個錯掉了。

 



 
#39008: Re: C++遞迴解法


jamil130011@gmail.com (許恩嘉)

學校 : 不指定學校
編號 : 249076
來源 : [1.174.49.241]
最後登入時間 :
2023-11-09 17:27:49
m933. 3. 邏輯電路 -- 2024年1月APCS | From: [1.174.63.23] | 發表日期 : 2024-01-07 23:19

啊啊啊因網路延遲多按了幾下送出,結果就變成重複回復4次了。

怎麼沒有刪除/修改留言的選項啊?

 





 
#39011: Re: C++遞迴解法


jamil130011@gmail.com (許恩嘉)

學校 : 不指定學校
編號 : 249076
來源 : [1.174.49.241]
最後登入時間 :
2023-11-09 17:27:49
m933. 3. 邏輯電路 -- 2024年1月APCS | From: [1.174.63.23] | 發表日期 : 2024-01-08 00:09

還是把完整程式碼附上好了。

#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
 
struct vr
{
int in1 = 0;//輸入端口1的索引
int in2 = 0;//輸入端口2的索引
short boool = -1;//這個電閥輸出
short aoxn = 0;//這個邏輯閥的種類,輸入端口與輸出端口不會用到此參數
int delay = -10;//電閥的延遲
};
vr* pfrs = nullptr;//因為懶得將指標作為函式的引數之一,乾脆宣告成全域變數
short check_boool(vr& fr);//檢查電閥的狀態
int check_delay(vr& fr);//檢查電閥的延遲
 
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int p, q, r, m;
cin >> p >> q >> r >> m;
vector<vr> frs(p + q + r + 1);
frs[0].delay = -1;//陣列第一項將是計算延遲時遞迴的終點。
for (int i = 1; i < p + 1; ++i) {
cin >> frs[i].boool;
frs[i].delay = -1;//輸入端口的延遲視為-1
}
int u, v;
for (int i = p + 1; i < p + q + 1; ++i) {
cin >> frs[i].aoxn;//輸入各個邏輯閥的種類
}
for (int i = 0; i < m; ++i) {
cin >> u >> v;
if (frs[v].in1 == 0) {
frs[v].in1 = u;//電閥的輸入端口1
}
else {
frs[v].in2 = u;//電閥的輸入端口2
}
}
 
pfrs = frs.data();//將全域變數pfrs指向vector<vr> frs的第一個元素,以便在函式中使用
int Max=0;
for (int i = p + q + 1; i < p + q + r + 1; ++i) {
Max = Max > check_delay(frs[i]) ? Max : frs[i].delay;
}
cout << Max << '\n';
for (int i = p + q + 1; i < p + q + r + 1; ++i) {
cout<<check_boool(frs[i])<<' ';
}
}
int check_delay(vr& fr) {//回傳該電閥的延遲
//如果delay成員不是預設值(-1),代表已計算過此電閥的延遲,直接回傳delay就可以了
if (fr.delay != -10) {
return fr.delay;
}
//否則計算此電閥的延遲,為兩個輸入電閥中的延遲較大者再加一
fr.delay = max(check_delay(pfrs[fr.in1]), check_delay(pfrs[fr.in2])) + 1;
return fr.delay;
}
 
short check_boool(vr& fr) {//回傳該電閥的輸出
//如果boool成員不是 -1 (預設值),代表已計算過此電閥的輸出,直接回傳boool就可以了
if (fr.boool != -1) {
return fr.boool;
}
//否則根據電閥種類進行遞迴,判斷此電閥的輸出
switch (fr.aoxn) {
case 0://輸出端口
fr.boool = check_boool(pfrs[fr.in1]);
return fr.boool;
case 1://AND 閘
fr.boool = check_boool(pfrs[fr.in1]) and check_boool(pfrs[fr.in2]) ? 1 : 0;
return fr.boool;
case 2://OR 閘
fr.boool = check_boool(pfrs[fr.in1]) or check_boool(pfrs[fr.in2]) ? 1 : 0;
return fr.boool;
case 3://XOR 閘
fr.boool = check_boool(pfrs[fr.in1]) xor check_boool(pfrs[fr.in2]) ? 1 : 0;
return fr.boool;
case 4://NOT 閘
fr.boool = !check_boool(pfrs[fr.in1]) ? 1 : 0;
return fr.boool;
}
}







 
ZeroJudge Forum