题目1
收获
1:这道题重点地还是如何理解题目,知道要找是否存在唯一拓扑的话,解决起来就很容易了~
代码
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
//有许多定义的方法,可以像我这样用参数的方法,同时如果不是递归的话,很多都可以使用全局变量解决~
//如果使用vector<int >g[n+1];这种定义方法的话,需要vector<int > g[]这种方法作为参数引用~
int islegel(vector<vector<int >>&g,vector<int >&input){
int count=0;
queue<int >q;
for(int i=1;i<=input.size();i++){
if(input[i]==0){
count++;
q.push(i);
}
if(count==2)
return 0;
}
while(!q.empty()){
if(q.size()>1)
return 0;
int u=q.front();
q.pop();
for(auto it:g[u]){
input[it]--;
if(input[it]==0)
q.push(it);
}
}
return 1;
}
int main()
{
int t;
cin>>t;
while(t--){
int n,m;
cin>>n>>m;
vector<vector<int >>g(n+1);
vector<int >input(n+1,0);
while(m--){
int x,y;
cin>>x>>y;
g[x].push_back(y);
input[y]++;
}
cout<<islegel(g,input)<<endl;
}
return 0;
}
题目2(求两个顶点之间的一条路径长度最短的路径)
收获
1:这道题的收获是,学会了用自己定义的数据结构,结合图进行遍历寻找到一条路径,最后进行逆序输出,这道题是一种广度优先搜索的方法,每次都统计当前层和前一层之间的节点关系,然后front节点从投开始依次遍历~
代码
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef struct{
int data;//顶点编号
int pre;
}Qu;
//非环形队列类型
void shortPath(vector<vector<int >>graph,int u,int v){
Qu q[100];
vector<bool>visited(graph.size(),false);
int front1=-1, rear=0;
q[rear].data=u;
q[rear].pre=-1;
visited[u]=true;
while(front1!=rear){
front1++;
int w=q[front1].data;
if(w==v){
int i=front1;
while(q[i].pre!=-1){
cout<<q[i].data<<' ';
i=q[i].pre;
}
cout<<q[i].data<<endl;
break;
}
for(auto it:graph[w]){
if(visited[it]==false){
visited[it]=true;
rear++;
q[rear].data=it;
q[rear].pre=front1;
}
}
}
}
int main()
{
int n,m;
cin>>n>>m;
vector<vector<int >>graph(n+1);
for(int i=0;i<m;i++){
int x,y;
cin>>x>>y;
graph[x].push_back(y);
graph[y].push_back(x);
}
int u,v;
cin>>u>>v;
shortPath(graph,u,v);
return 0;
}
题目3(所有可能的路径)
给你一个有 n 个节点的 有向无环图(DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序)
graph[i] 是一个从节点 i 可以访问的所有节点的列表(即从节点 i 到节点 graph[i][j] 存在一条有向边)。
示例 1:
输入:graph = [[1,2],[3],[3],[]]
输出:[[0,1,3],[0,2,3]]
解释:有两条路径 0 -> 1 -> 3 和 0 -> 2 -> 3
示例 2:
输入:graph = [[4,3,1],[3,2,4],[3],[4],[]]
输出:[[0,4],[0,3,4],[0,1,3,4],[0,1,2,3,4],[0,1,4]]
提示:
n == graph.length
2 <= n <= 15
0 <= graph[i][j] < n
graph[i][j] != i(即不存在自环)
graph[i] 中的所有元素 互不相同
保证输入为 有向无环图(DAG)
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/all-paths-from-source-to-target
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
收获
1:这是自己做的第一道图的题,感觉好像和自己学习中学到的C语言写的图有丢丢区别,原来可以使用位置i表示一个节点,然后vector数组中的元素值表示节点连接的位置,这样也表示出来了一个图的样子,然后使用深度优先搜索添加路径,因为最开始已经有一个固定的值0,所以在最开始提前添加,然后仍然通过,循环和递归的方法实现回溯添加路径(这里自己好像感觉,如果想要获得路径的话,就要使用循环和递归的方法,单纯的递归有时好像会出现数组空等的问题)
2:感觉这里大概用了某种思想,深度递归一定会找到任何一点自己想要找的值,如果当前路径没有找到的话,就会选择回溯,结束当次循环~
代码
class Solution {
public:
vector<vector<int >> result;
vector<int >path;
void dfs(vector<vector<int >>&graph,int x){
//找到符合条件的一条路径
if(x==graph.size()-1){
result.push_back(path);
return;
}
//遍历当前节点的所有链接的节点
for(int i=0;i<graph[x].size();i++){
//遍历到的节点加入到路径
path.push_back(graph[x][i]);
dfs(graph,graph[x][i]);
//回溯,撤销本节点
path.pop_back();
}
}
vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
path.push_back(0);
dfs(graph,0);
return result;
}
};
题目4(克隆图)
给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。
图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。
class Node {
public int val;
public List neighbors;
}
测试用例格式:
简单起见,每个节点的值都和它的索引相同。例如,第一个节点值为 1(val = 1),第二个节点值为 2(val = 2),以此类推。该图在测试用例中使用邻接列表表示。
邻接列表 是用于表示有限图的无序列表的集合。每个列表都描述了图中节点的邻居集。
给定节点将始终是图中的第一个节点(值为 1)。你必须将 给定节点的拷贝 作为对克隆图的引用返回。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/clone-graph
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
收获
1:学会了图的深度优先搜索克隆!结合map和深度优先~
代码
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> neighbors;
Node() {
val = 0;
neighbors = vector<Node*>();
}
Node(int _val) {
val = _val;
neighbors = vector<Node*>();
}
Node(int _val, vector<Node*> _neighbors) {
val = _val;
neighbors = _neighbors;
}
};
*/
class Solution {
public:
unordered_map<Node*,Node*>visited;
Node* cloneGraph(Node* node) {
if(node==nullptr){
return node;
}
if(visited.find(node)!=visited.end()){
return visited[node];
}
Node *cloneNode=new Node(node->val);
visited[node]=cloneNode;
/*for(auto&neighbor:node->neighbors){
cloneNode->neighbors.emplace_back(cloneGraph(neighbor));
}*/
for(int i=0;i<node->neighbors.size();i++){
cloneNode->neighbors.push_back(cloneGraph(node->neighbors[i]));
}
return cloneNode;
}
};
题目5(课程表)
你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。
例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。
请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。
示例 1:
输入:numCourses = 2, prerequisites = [[1,0]]
输出:true
解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。
示例 2:
输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
输出:false
解释:总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。
提示:
1 <= numCourses <= 105
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i] 中的所有课程对 互不相同
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/course-schedule
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
收获
1:学会了一些关于图的出度入度的应用,课程表这道题是典型的应用,自己 在上课的时候也学过相关的知识(1)统计所有入度为0的节点入队列(2)遍历每一个队列的节点,将所有该点相关的映射的入度-1,如果减去1之后对应的入度变为0,那么就添加近队列,继续遍历队列~(3)最后统计最终结果的总数
2:最开始全部采用遍历的方法,没有巧妙的使用map这一方法,在最开始第一次遍历创建input时,同时创建每一个节点的出度映射,这样在后期对每一个节点相应的临界点入度-1时会比较方便,不会超时~
代码
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<int >input(numCourses,0);
//统计所有入度为0的节点
unordered_map<int,vector<int >>mp;
for(auto&pre:prerequisites){
input[pre[0]]++;
mp[pre[1]].push_back(pre[0]);
}
queue<int >q;
for(int i=0;i<numCourses;i++){
if(input[i]==0)
q.push(i);
}
//出队列的时候将这个顶点所有的临界点的入度减1,并将队列的结果元素加入结合,如果入度为0
//则继续入队列
//最后检查结果集合中的元素是否和课程数相同
int count=0;
while(!q.empty()){
int node=q.front();
q.pop();
count++;
for(auto&num:mp[node]){
input[num]--;
if(input[num]==0)
q.push(num);
}
}
return count==numCourses;
}
};