PTA 天梯赛 L3-025:那就别担心了 ← 中国电子学会青少年软件编程等级考试(2024年C++四级)+ 链式前向星 / 邻接表

【题目来源】
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



 

### PTA 天梯赛 L1-98 题目解析 对于PTA天梯赛L1-98题目的讨论,注意到该题目并未直接出现在提供的参考资料中。然而,在处理这类竞赛编程问题时,通常涉及算法设计、数据结构应用以及边界条件的考虑。 #### 输入与输出说明 假设此题要求处理某种形式的数据转换或计算,输入部分可能包含一组或多组测试案例,每组案例由若干参数构成。输出则依据具体逻辑得出的结果展示。例如: - **输入**:多组整数或其他类型的数值。 - **输出**:基于特定规则变换后的结果集。 #### 关键点分析 尽管具体的L1-98题目细节未知,但从其他类似题目[^1]可以推测出一些常见的考察方向: - 对于涉及到“加权求和”的情况,需注意实际操作并非按比例分配权重,而是简单相乘。 - 当遇到日期时间类问题时,应特别留意格式化输入输出的要求,比如六位或四位表示法下的份月份解析[^2]。 - 判断奇偶性的实现可以通过位运算来优化性能,减少不必要的资源消耗[^3]。 - 字符串处理方面,当面临长度调整需求时(如截断或填充),应当先对比目标长度同现有字符串长度的关系再做相应操作[^4]。 由于缺乏针对L1-98的具体描述,上述内容仅作为一般性指导原则提供参考价值。为了更精准地解答此类问题,建议查阅官方文档或者过往比赛记录获取最权威的信息源。 ```cpp // 示例代码框架用于解决假定的任务场景 #include <iostream> using namespace std; int main(){ // 假设读入两个正整数a,b并输出它们的最大公约数gcd(a, b) int a, b; cin >> a >> b; while(b != 0){ int temp = b; b = a % b; a = temp; } cout << "GCD is: " << a << endl; return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值