图论刷题

卡码网 98. 所有可达路径

使用邻接矩阵存储:

#include
#include
using namespace std;
 vector>res;//收集符合条件的路径
    vectorpath;//0节点到终点的路径
    //确定递归函数 参数和返回值
    void dfs(const vector>& graph,int x,int n){
        //确定终止条件
        if(x==n){
            res.push_back(path);
            return;
        }
        //确定单层递归逻辑
        for(int i=1;i<=n;i++){//寻找x节点指向的节点
            if(graph[x][i]==1){
                path.push_back(i);
                dfs(graph,i,n);
                path.pop_back();
            }
        }
    }
int main(){
   int n,m,s,t;
   //输入数据
   cin>>n>>m;
   vector>graph(n+1,vector(n+1,0));
   while(m--){
       cin>>s>>t;
       graph[s][t]=1;
   }
   //遍历
    path.push_back(1);
    dfs(graph,1,n);
    //输出数据
    if(res.size()==0)cout<<-1<& pa:res){
        for(int i=0;i

使用邻接表存储:

#include
#include
#include
using namespace std;
 vector>res;//收集符合条件的路径
    vectorpath;//0节点到终点的路径
    //确定递归函数 参数和返回值
    void dfs(const vector>& graph,int x,int n){
        //确定终止条件
        if(x==n){
            res.push_back(path);
            return;
        }
        //确定单层递归逻辑
        for(int i:graph[x]){//寻找x节点指向的节点
                path.push_back(i);
                dfs(graph,i,n);
                path.pop_back();
        }
    }
int main(){
   int n,m,s,t;
   //输入数据
   cin>>n>>m;
   vector>graph(n+1);
   while(m--){
       cin>>s>>t;
       graph[s].push_back(t);
   }
   //遍历
    path.push_back(1);
    dfs(graph,1,n);
    //输出数据
    if(res.size()==0)cout<<-1<& pa:res){
        for(int i=0;i

卡码网 99. 岛屿数量

dfs搜索:

#include
#include
using namespace std;

int dir[4][2]={0,1,1,0,0,-1,-1,0};//右下左上 四个方向
//确定递归函数参数和返回值
void dfs(const vector>& grid,vector>& visited,int x,int y){
    //确定终止条件
    //if(visited[x][y]==true||grid[x][y]==0)return;
    //不能加这个终止,我在上一层已经把状态变为true,我就是要遍历这个点的四周的,你
    //给我终止了,破坏了我的遍历
    //确定单层递归逻辑
    for(int i=0;i<4;i++){
        int nextx=x+dir[i][0];
        int nexty=y+dir[i][1];
        if(nextx<0||nextx>=grid.size()||nexty<0||nexty>=grid[0].size())continue;
        if(grid[nextx][nexty]==1&&visited[nextx][nexty]==false){
            visited[nextx][nexty]=true;
            dfs(grid,visited,nextx,nexty);
            //不需要回溯,就是要dfs遍历一遍把周围的陆地都标记一下
        }
    }
}
int main(){
    //输入数据
    int n,m;
    cin>>n>>m;
    vector>grid(n,vector(m,0));
    for(int x=0;x>grid[x][y];
        }
    }
    vector>visited(n,vector(m,false));
    //处理数据
    int res=0;
    for(int i=0;i

bfs搜索

#include
#include
#include
using namespace std;

int dir[4][2]={0,1,1,0,0,-1,-1,0};//右下左上 四个方向

//确定递归函数参数和返回值
void bfs(const vector>& grid,vector>& visited,int x,int y){
    //确定终止条件
    //确定单层递归逻辑
    queue>que;
    que.push({x,y});
    visited[x][y]=true;
    while(!que.empty()){
        pairpa=que.front();
        que.pop();
        int curx=pa.first;
        int cury=pa.second;
        for(int i=0;i<4;i++){
            int nextx=curx+dir[i][0];
            int nexty=cury+dir[i][1];
            if(nextx<0||nextx>=grid.size()||nexty<0||nexty>=grid[0].size())continue;
            if(grid[nextx][nexty]==1&&visited[nextx][nexty]==false){
                que.push({nextx,nexty});
                visited[nextx][nexty]=true;
            }
        }
    }
    
}
int main(){
    //输入数据
    int n,m;
    cin>>n>>m;
    vector>grid(n,vector(m,0));
    for(int x=0;x>grid[x][y];
        }
    }
    vector>visited(n,vector(m,false));
    //处理数据
    int res=0;
    for(int i=0;i

分析:对于这道题,dfs与bfs的做法,dfs函数中还有对dfs函数本身的调用;bfs函数中没有对bfs函数本身的调用,bfs做法中,对一个点进行bfs函数,把这个点压入队列中,让后从队列中取出点,对点的四周进行遍历,如果符合条件,就把点压入队列中,让后函数一直持续从队列中取数进行遍历,直到队列中为空。

100. 岛屿的最大面积

dfs法一:(dfs函数处理下一个节点,不需要再写终止条件,因为终止条件包含在单层循环处理中)

#include
#include
using namespace std;

int dir[4][2]={0,1,1,0,0,-1,-1,0};
int count=0;
//dfs处理下一个节点
//确定递归函数参数和返回值
void dfs(vector>& grid,vector>& visited,int x,int y){
    for(int i=0;i<4;i++){
        int nextx=x+dir[i][0];
        int nexty=y+dir[i][1];
        if(nextx<0||nextx>=grid.size()||nexty<0||nexty>=grid[0].size()) continue;
        if(visited[nextx][nexty]==false&&grid[nextx][nexty]==1){
            count++;
            visited[nextx][nexty]=true;
            dfs(grid,visited,nextx,nexty);
        }
    }
}

int main(){
    //输入数据
    int res=0;
    int n,m;
    cin>>n>>m;
    vector>grid(n,vector(m,0));
    for(int i=0;i>grid[i][j];
        }
    }
    vector>visited(n,vector(m,false));
    //处理数据
    for(int i=0;i

dfs法二(dfs处理当前节点,需要写终止条件)

#include
#include
using namespace std;

int dir[4][2]={0,1,1,0,0,-1,-1,0};
int count=0;
//dfs处理当前节点
//确定递归函数参数和返回值
void dfs(vector>& grid,vector>& visited,int x,int y){
    //确定终止条件
    if(grid[x][y]==0||visited[x][y]==true) return;
    //确定单层递归逻辑
    count++;
    visited[x][y]=true;
    for(int i=0;i<4;i++){
        int nextx=x+dir[i][0];
        int nexty=y+dir[i][1];
        if(nextx<0||nextx>=grid.size()||nexty<0||nexty>=grid[0].size()) continue;
        dfs(grid,visited,nextx,nexty);
    }
}

int main(){
    //输入数据
    int res=0;
    int n,m;
    cin>>n>>m;
    vector>grid(n,vector(m,0));
    for(int i=0;i>grid[i][j];
        }
    }
    vector>visited(n,vector(m,false));
    //处理数据
    for(int i=0;i

方法三:(bfs遍历)

#include
#include
#include
using namespace std;

int dir[4][2]={0,1,1,0,0,-1,-1,0};
int count=0;
//dfs处理当前节点
//确定递归函数参数和返回值
void bfs(vector>& grid,vector>& visited,int x,int y){
    //确定单层递归逻辑
    queue>que;
    que.push({x,y});
    count++;
    visited[x][y]=true;
    while(!que.empty()){
        pairpa=que.front();que.pop();
        int xx=pa.first;
        int yy=pa.second;
        for(int i=0;i<4;i++){
            int nextx=xx+dir[i][0];
            int nexty=yy+dir[i][1];
            if(nextx<0||nextx>=grid.size()||nexty<0||nexty>=grid[0].size()) continue;
            if(grid[nextx][nexty]==1&&visited[nextx][nexty]==false){
                que.push({nextx,nexty});
                count++;
                visited[nextx][nexty]=true;
            }
        }
    }
}

int main(){
    //输入数据
    int res=0;
    int n,m;
    cin>>n>>m;
    vector>grid(n,vector(m,0));
    for(int i=0;i>grid[i][j];
        }
    }
    vector>visited(n,vector(m,false));
    //处理数据
    for(int i=0;i

101. 孤岛的总面积

用dfs遍历

#include
#include
using namespace std;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
//确定递归函数参数和返回值
//该dfs是为了把靠边缘的岛屿变成海洋
void dfs(vector>& grid,int x,int y){
    //确定单层递归逻辑
    grid[x][y]=0;
    for(int i=0;i<4;i++){
        int nextx=x+dir[i][0];
        int nexty=y+dir[i][1];
        if(nextx<0||nextx>=grid.size()||nexty<0||nexty>=grid[0].size()){
            continue;
        }
        if(grid[nextx][nexty]==0) continue;
        dfs(grid,nextx,nexty);
    }
    
}
int main(){
    //输入数据
    int n,m;
    cin>>n>>m;
    vector>grid(n,vector(m,0));
    for(int i=0;i>grid[i][j];
        }
    }
    //处理数据
    //遍历挨着边缘的岛屿
    for(int i=0;i

使用bfs遍历:

#include
#include
#include
using namespace std;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
//确定递归函数参数和返回值
//该bfs是为了把靠边缘的岛屿变成海洋
void bfs(vector>& grid,int x,int y){
    //确定单层递归逻辑
    grid[x][y]=0;
    queue>que;
    que.push({x,y});
    while(!que.empty()){
        pairpa;
        pa=que.front();que.pop();
        int xx=pa.first;
        int yy=pa.second;
        for(int i=0;i<4;i++){
            int nextx=xx+dir[i][0];
            int nexty=yy+dir[i][1];
            if(nextx<0||nextx>=grid.size()||nexty<0||nexty>=grid[0].size()){
                continue;
            }
            if(grid[nextx][nexty]==0) continue;
            que.push({nextx,nexty});
            grid[nextx][nexty]=0;
        }
    }
    
}
int main(){
    //输入数据
    int n,m;
    cin>>n>>m;
    vector>grid(n,vector(m,0));
    for(int i=0;i>grid[i][j];
        }
    }
    //处理数据
    //遍历挨着边缘的岛屿
    for(int i=0;i

102. 沉没孤岛

使用dfs遍历

#include
#include
using namespace std;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
//确定递归函数参数和返回值
//该dfs是为了把靠边缘的岛屿用2标记,让后主函数中再遍历把2变成1,1变成0
void dfs(vector>& grid,int x,int y){
    //确定单层递归逻辑
    grid[x][y]=2;
    for(int i=0;i<4;i++){
        int nextx=x+dir[i][0];
        int nexty=y+dir[i][1];
        if(nextx<0||nextx>=grid.size()||nexty<0||nexty>=grid[0].size()){
            continue;
        }
        if(grid[nextx][nexty]==0||grid[nextx][nexty]==2) continue;
        dfs(grid,nextx,nexty);
    }
    
}
int main(){
    //输入数据
    int n,m;
    cin>>n>>m;
    vector>grid(n,vector(m,0));
    for(int i=0;i>grid[i][j];
        }
    }
    //处理数据
    //遍历挨着边缘的岛屿
    for(int i=0;i

使用bfs遍历

#include
#include
#include
using namespace std;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
//确定递归函数参数和返回值
//该bfs是为了把靠边缘的岛屿用2标记,让后主函数中再遍历把2变成1,1变成0
void bfs(vector>& grid,int x,int y){
    //确定单层递归逻辑
    grid[x][y]=2;
    queue>que;
    que.push({x,y});
    while(!que.empty()){
        pairpa;
        pa=que.front();que.pop();
        int xx=pa.first;
        int yy=pa.second;
        for(int i=0;i<4;i++){
            int nextx=xx+dir[i][0];
            int nexty=yy+dir[i][1];
            if(nextx<0||nextx>=grid.size()||nexty<0||nexty>=grid[0].size()){
                continue;
            }
            if(grid[nextx][nexty]==0||grid[nextx][nexty]==2) continue;
            que.push({nextx,nexty});
            grid[nextx][nexty]=2;
        }
    }
    
}
int main(){
    //输入数据
    int n,m;
    cin>>n>>m;
    vector>grid(n,vector(m,0));
    for(int i=0;i>grid[i][j];
        }
    }
    //处理数据
    //遍历挨着边缘的岛屿
    for(int i=0;i

103. 水流问题

#include
#include
using namespace std;

int dir[4][2]={0,1,1,0,0,-1,-1,0};

//确定递归函数 参数
//该dfs遍历,是对当前节点进行处理。从边缘逆流遍历,标记能到达边缘的坐标
void dfs(vector>& grid,vector>& visited,int x,int y){
    //确定终止条件
    if(visited[x][y]==true) return;
    //确定单层递归逻辑
    visited[x][y]=true;
    for(int i=0;i<4;i++){
        int nextx=x+dir[i][0];
        int nexty=y+dir[i][1];
        if(nextx<0||nextx>=grid.size()||nexty<0||nexty>=grid[0].size()){
            continue;
        }
        if(grid[x][y]>grid[nextx][nexty]) continue;
        dfs(grid,visited,nextx,nexty);
    }
}

int main(){
    //输入数据
    int n,m;
    cin>>n>>m;
    vector>grid(n,vector(m,0));
    for(int i=0;i>grid[i][j];
        }
    }
    //处理数据
    vector>firstBorder(n,vector(m,false));
    vector>secondBorder(n,vector(m,false));
    //从边缘进行dfs遍历,标记目的单元格
    for(int i=0;i

104. 建造最大岛屿

#include
#include
#include
#include
using namespace std;
int dir[4][2]={0,1,1,0,-1,0,0,-1};
int count;
//确定递归函数参数
//该dfs是将每个岛屿染成不同的颜色,并计算每个岛屿的面积大小
void dfs(vector>& grid,vector>& visited,int x,int y,int mark){
    //确定终止条件
    if(grid[x][y]==0||visited[x][y]) return;
    //确定单层递归逻辑
    visited[x][y]=true;
    count++;
    grid[x][y]=mark;
    for(int i=0;i<4;i++){
        int nextx=x+dir[i][0];
        int nexty=y+dir[i][1];
        if(nextx<0||nextx>=grid.size()||nexty<0||nexty>=grid[0].size()) continue;
        dfs(grid,visited,nextx,nexty,mark);
    }
}

int main(){
    //输入数据
    int n,m;
    cin>>n>>m;
    vector>grid(n,vector(m,0));
    for(int i=0;i>grid[i][j];
        }
    }
    vector>visited(n,vector(m,false));
    //处理数据
    unordered_map gridNum;//记录每个岛屿的面积
    int mark=2;//记录每个岛屿的编号
    bool isAllGrid=true;//标记是否整个地图都是陆地
    for(int i=0;ivisitedGrid;//标记访问过的岛屿
    for(int i=0;i=grid.size()||neary<0||neary>=grid[0].size()){
                        continue;
                    }
                    if(visitedGrid.count(grid[nearx][neary]))continue;//添加过的岛屿不要重复添加
                    count+=gridNum[grid[nearx][neary]];
                    visitedGrid.insert(grid[nearx][neary]);
                }
            }
            res=max(res,count);
        }
    }
    cout<

思路真的感觉很难想,而且代码很难实现。不过这道题应该还是要练图论的遍历,用的dfs遍历,感觉对图论的遍历更加掌握了。

110. 字符串接龙

#include
#include
#include
#include
#include
#include
using namespace std;
int main(){
    //输入数据
    int n;
    cin>>n;
    string str,beginStr,endStr;
    cin>>beginStr>>endStr;
    unordered_set strSet;
    for(int i=0;i>str;
        strSet.insert(str);
    }
    //处理数据
    //转换的字符串之间只相差一个字符,字符串之间的连接形成了一个无向图,
    //遍历无向图,找到最短路径,使用广搜。
    //尝试替换每一个字符,如果在set字典中找到,并且没有没遍历过,
    //就可以加入que中,加入map中保存
    queueque;
    que.push(beginStr);//初始化队列
    unordered_mapstrMap;//map用来记录遍历长度,验证是否遍历过
    strMap.insert(pair(beginStr,1));//初始化map
    while(!que.empty()){
        string word=que.front();
        que.pop();
        int path=strMap[word];
        //轮流替换每个字符
        for(int i=0;i(newword,path+1));
                }
            }
        }
    }
    cout<<0<

105. 有向图的完全可达性

#include
#include
#include
using namespace std;

//确定递归函数参数  使用dfs遍历
void dfs(const vector>& grid,vector& visited,int key){
    //dfs处理当前节点
    if(visited[key]) return;
    //确定单层递归逻辑
    visited[key]=true;
    listkeys=grid[key];
    for(int key : keys){
        dfs(grid,visited,key);
    }
}

int main(){
    //输入数据
    int n,k,s,t;
    cin>>n>>k;
    //使用邻接表保存图
    vector> grid(n+1);
    while(k--){
        cin>>s>>t;
        grid[s].push_back(t);
   }
   //处理数据
   vector visited(n+1,false);
   dfs(grid,visited,1);
   for(int i=1;i<=n;i++){
       if(visited[i]==false) {
           cout<<-1<

dfs遍历 细微差别

#include
#include
#include
using namespace std;

//确定递归函数参数  使用dfs遍历
void dfs(const vector>& grid,vector& visited,int key){
    //dfs处理下一个节点
    //确定单层递归逻辑
    listkeys=grid[key];
    for(int key : keys){
        if(visited[key])continue;
        visited[key]=true;
        dfs(grid,visited,key);
    }
}

int main(){
    //输入数据
    int n,k,s,t;
    cin>>n>>k;
    //使用邻接表保存图
    vector> grid(n+1);
    while(k--){
        cin>>s>>t;
        grid[s].push_back(t);
   }
   //处理数据
   vector visited(n+1,false);
   visited[1]=true;
   dfs(grid,visited,1);
   for(int i=1;i<=n;i++){
       if(visited[i]==false) {
           cout<<-1<

通过bfs遍历

#include
#include
#include
#include
using namespace std;

//确定递归函数参数  使用bfs遍历
void bfs(const vector>& grid,vector& visited,int key){
    //确定单层递归逻辑
    queueque;
    que.push(key);
    while(!que.empty()){
        int cur=que.front();
        que.pop();
        listkeys=grid[cur];
        for(int key:keys){
            if(visited[key]) continue;
            visited[key]=true;
            que.push(key);
        }
    }
}

int main(){
    //输入数据
    int n,k,s,t;
    cin>>n>>k;
    //使用邻接表保存图
    vector> grid(n+1);
    while(k--){
        cin>>s>>t;
        grid[s].push_back(t);
   }
   //处理数据
   vector visited(n+1,false);
   visited[1]=true;
   bfs(grid,visited,1);
   for(int i=1;i<=n;i++){
       if(visited[i]==false) {
           cout<<-1<

106. 岛屿的周长

#include
#include
using namespace std;
int dir[4][2]={0,1,1,0,-1,0,0,-1};
int main(){
    int n,m;
    cin>>n>>m;
    vector>grid(n,vector(m,0));
    for(int i=0;i>grid[i][j];
        }
    }
    
    int res=0;
    for(int i=0;i=n||y<0||y>=m||grid[x][y]==0)res++;
                }
            }
        }
    }
    cout<

107. 寻找存在的路径

#include
#include
using namespace std;
//确定节点数量
int n=105;
//根节点数组
vectorfather(n,0);
//并查集初始化
void init(){
    for(int i=0;iu加入到并查集中
void ioin(int u,int v){
    u=find(u);
    v=find(v);
    if(u==v) return ;
    father[v]=u;
}
int main(){
    int m,s,t,source,destination;
    cin>>n>>m;
    init();
    for(int i=0;i>s>>t;
        ioin(s,t);
    }
    cin>>source>>destination;
    if(isSame(source,destination))cout<<1<

108. 冗余连接

#include
#include
using namespace std;
//确定节点个数
int n=1005;
vectorfather(n,0);
//初始化并查集
void init(){
    for(int i=0;iu加入到并查集中
void join(int u,int v){
    u=find(u);
    v=find(v);
    if(u==v)return;
    father[v]=u;
}
int main(){
    int s,t;
    cin>>n;
    init();
    for(int i=0;i>s>>t;
        if(isSame(s,t)){
            cout<

109. 冗余连接II

#include
#include
using namespace std;

int n=1005;
vectorfather(n,0);
//并查集初始化
void init(){
    for(int i=0;iu加入并查集中
void join(int u,int v){
    u=find(u);
    v=find(v);
    if(u==v)return;
    father[v]=u;
}
bool isTreeAfterRemoveEdge(vector>& edges,int deleedge){
    //删除某边,利用并查集看是否构成有向树。或者删除另一条边。
    init();
    for(int i=0;i>& edges){
    //依次将各个边加入并查集中,同时看是否构成环
    init();
    for(int i=0;i>n;
    vector>edges;//保存有向边
    vectorinDegree(n,0);
    for(int i=0;i>s>>t;
        inDegree[t]++;//入度加一
        edges.push_back({s,t});
    }
    //处理数据  考虑三种情况
    //寻找有没有入度为2的,如果有,找到对应的两条边,删除某边,利用isTreeAfterRemoveEdge函数
    //为了保证最先删除的是最后输入的边,将两条边提取出来,按一定顺序尝试删除
    //情况三,入度没有2的,则是构成了单向环,利用getMoveEdge函数
    
    vectorvec;//记录指向入度为2的点
    //寻找度为2的
    for(int i=n-1;i>=0;i--){
        if(inDegree[edges[i][1]]==2){
            vec.push_back(i);
        }
    }
    //情况一,二
    if(vec.size()==2){
        if(isTreeAfterRemoveEdge(edges,vec[0])){
            cout<

53. 寻宝(第七期模拟笔试)

最小生成树 prim算法

#include
#include
#include
using namespace std;

int main(){
    int v,e,s,p,t;
    cin>>v>>e;
    vector>grid(v+1,vector(v+1,10001));//存储图
    for(int i=1;i<=e;i++){
        cin>>s>>p>>t;
        grid[s][p]=t;
        grid[p][s]=t;//存储边及权值
    }
    
    vectorisIntree(v+1,false);//是否在树里
    
    //所有节点到最小生成树的最小距离
    
    vectorminDist(v+1,10001);
    //需要执行n-1次三部曲,将边加入到最小生成树中
    for(int i=1;i

53. 寻宝(第七期模拟笔试)

最小生成树 kruskal算法

#include
#include
#include
using namespace std;

int n=10001;//节点数量
vector father(n,0);
//初始化并查集
void init(){
    for(int i=1;iu加入到并查集中
void join(int u,int v){
    u=find(u);
    v=find(v);
    if(u==v)return;
    father[v]=u;
}

struct edge{
    int l,r,val;
};
int main(){
    //输入数据
    int v,e,r,s,t;
    cin>>v>>e;
    vectoredges(e+1);
    for(int i=1;i<=e;i++){
        cin>>r>>s>>t;
        edges.push_back({r,s,t});
    }
    //处理数据 
    //为edges排序,接着遍历,如果不构成环,就把边加入到并查集中,
    //同时累加权值
    int res_val=0;
    init();
    sort(edges.begin(),edges.end(),[](const edge& a,const edge& b){
        return a.val

117. 软件构建

#include
#include
#include
#include
using namespace std;

int main(){
    //输入数据
    int n,m,s,t;
    cin>>n>>m;
    unordered_map>umap(n);//记录文件间依赖关系
    vectorinDegree(n,0);
    for(int i=0;i>s>>t;//先处理s再处理t
        umap[s].push_back(t);
        inDegree[t]++;//t的入度+1
    }
    //处理数据
    //1.找到入度为0的点,2.让其后缀节点入度减一。重复这两点
    queueque;
    for(int i=0;ires;//记录处理顺序结果
    while(!que.empty()){
        int cur=que.front();
        que.pop();
        res.push_back(cur);
        vectorfiles;//保存入度为0节点的后缀节点
        files=umap[cur];
        for(int i=0;i

47. 参加科学大会(第六期模拟笔试)

有向图中最短路径 dijkstra 算法朴素版

#include
#include
#include
using namespace std;
//有向图中求最短路径。三部曲做题法
//数据的存储:二维数组存有向边及权值;visited数组;minDist数组:(保存各节点到源点的最短距离)
//第一步:寻找距离源点最近的节点
//第二步:更新节点为已访问
//第三步:更新未访问节点到源点的最短距离
int main(){
    //输入数据
    int n,m,s,e,v;
    cin>>n>>m;
    vector>grid(n+1,vector(n+1,INT_MAX));
    for(int i=1;i<=m;i++){
        cin>>s>>e>>v;
        grid[s][e]=v;
    }
    vectorvisited(n+1,false);//标记节点是否被访问
    vectorminDist(n+1,INT_MAX);//
    //处理数据
    //需要循环处理三步曲n次,
    minDist[1]=0;
    for(int i=1;i<=n;i++){
        //第一步
        int cur=1;
        int minval=INT_MAX;
        for(int j=1;j<=n;j++){
            if(!visited[j]&&minDist[j]

47. 参加科学大会(第六期模拟笔试)

有向图中最短路径 dijkstra 算法堆优化版

#include
#include
#include
#include
#include
using namespace std;
//该方法也符合三部曲,朴素版是通过遍历n次(节点个数)三部曲,每次将一个节点加入集合中
//堆优化版是用小顶堆对边进行排序,每次选择最短的边,和kruskal思想相似
//数据准备:visited数组,minDist数组,grid数组+邻接表,优先队列
//第一步:取出小顶堆堆顶数据,(堆自动排序了)
//第二步:标记节点已访问
//第三步:更新cur节点链接的节点到源点的最短距离,加入优先队列中


//构造一个结构体表示邻接表
struct Edge{
    int to;//临间顶点
    int val;//边的权重
    Edge(int t,int w):to(t),val(w){}//构造函数
};
//小顶堆
class mycomparison{
public:
//操作符重载函数
    bool operator()(const pair& lhs,const pair& rhs){
        return lhs.second>rhs.second;//注意是大于,我也不知道为啥
    }    
};

int main(){
    //输入数据
    int n,m,s,e,v;
    cin>>n>>m;
    vector>grid(n+1);
    for(int i=0;i>s>>e>>v;
        grid[s].push_back(Edge(e,v));
    }
    vectorvisited(n+1,false);
    vectorminDist(n+1,INT_MAX);
    //pair 表示<节点,节点到源点的权值>
    priority_queue,vector>,mycomparison> pq;
    //处理数据
    pq.push(pair(1,0));
    minDist[1]=0;
    
    //在队列不为空条件下进行三部曲的重复
    while(!pq.empty()){
        //第一步
        paircur=pq.top();
        pq.pop();
        //第二步
        visited[cur.first]=true;
        //第三步
        for(Edge edge:grid[cur.first]){
            if(!visited[edge.to]&&minDist[cur.first]+edge.val(edge.to,minDist[edge.to]));
            }
        }
    }
    if(minDist[n]==INT_MAX) cout<<-1<

dijkstra算法 不能用于权值有负数的情况

94. 城市间货物运输 I

Bellman_ford 算法

#include
#include
#include
using namespace std;
//对于权值有负值的求单项图的最短路径问题
//松弛n-1次(n个节点)
//每次松弛遍历单向边,更新终点到源点的最短距离
int main(){
    //输入数据
    int n,m,s,t,v;
    cin>>n>>m;
    vector>grid;
    for(int i=0;i>s>>t>>v;
        grid.push_back({s,t,v});
    }
    //处理数据
    vectorminDist(n+1,INT_MAX);
    minDist[1]=0;
    for(int i=1;i &vec:grid){//加&可以避免循环时复制vector数组而产生的时间和空间开销
            int from=vec[0];
            int to=vec[1];
            int val=vec[2];
            if(minDist[from]!=INT_MAX&&minDist[to]>minDist[from]+val){
                minDist[to]=minDist[from]+val;
            }
        }
    }
    if(minDist[n]==INT_MAX) cout<<"unconnected"<

Bellman_ford 算法优化版本

#include
#include
#include
#include
#include
using namespace std;
//对bellman_ford 算法 进行优化,
//使用isInQueue数组,queue队列,减少无效次数的松弛
//构建结构体
struct Edge{
      int to;
      int val;
      Edge(int k,int w):to(k),val(w){}//构造函数
};
int main(){
    //输入数据
    int n,m,s,t,v;
    cin>>n>>m;
    vector>grid(n+1);
    for(int i=0;i>s>>t>>v;
        grid[s].push_back(Edge(t,v));
    }
    //处理数据
    vectorminDist(n+1,INT_MAX);
    vectorisInQueue(n+1,false);
    minDist[1]=0;
    queueque;
    que.push(1);
    isInQueue[1]=true;
    //进行松弛
    while(!que.empty()){
        int node=que.front();
        que.pop();
        isInQueue[node]=false;
        for(Edge &edge:grid[node]){
            int from=node;
            int to=edge.to;
            int val=edge.val;
            if(minDist[from]!=INT_MAX&&minDist[to]>minDist[from]+val){
                minDist[to]=minDist[from]+val;
                if(!isInQueue[to]) {
                    que.push(to);
                    isInQueue[to]=true;
                }
            }
        }
    }
    if(minDist[n]==INT_MAX) cout<<"unconnected"<

95. 城市间货物运输 II

#include
#include
#include
using namespace std;
//本题存在负权回路的情况,正常只需要松弛n-1次就可以找到所有节点到源点的最短距离
//那么再多松弛一次,看minDist数组是否变化,有变化则存在负权回路
int main(){
    //输入数据
    int n,m,s,t,v;
    cin>>n>>m;
    vector>grid;
    for(int i=0;i>s>>t>>v;
        grid.push_back({s,t,v});
    }
    //处理数据
    vectorminDist(n+1,INT_MAX);
    minDist[1]=0;
    bool fact=false;
    //进行n次松弛
    for(int i=1;i<=n;i++){
        for(vector& vec:grid){
            int from=vec[0];
            int to=vec[1];
            int val=vec[2];
            if(iminDist[from]+val)
                minDist[to]=minDist[from]+val;
            }
            else {
                if(minDist[from]!=INT_MAX&&minDist[to]>minDist[from]+val)
                fact=true;
            }
        }
    }
    if(fact) cout<<"circle"<

SPFA法

#include
#include
#include
#include
#include
using namespace std;
//对bellman_ford 算法 进行优化,
//使用isInQueue数组,queue队列,减少无效次数的松弛
//构建结构体
struct Edge{
      int to;
      int val;
      Edge(int k,int w):to(k),val(w){}//构造函数
};
int main(){
    //输入数据
    int n,m,s,t,v;
    cin>>n>>m;
    vector>grid(n+1);
    for(int i=0;i>s>>t>>v;
        grid[s].push_back(Edge(t,v));
    }
    //处理数据
    vectorminDist(n+1,INT_MAX);
    vectorisInQueue(n+1,false);
    vectorcount(n+1,0);//记录节点加入队列的次数
    minDist[1]=0;
    queueque;
    que.push(1);
    count[1]=1;
    bool fact=false;
    //进行松弛
    while(!que.empty()){
        int node=que.front();
        que.pop();
        for(Edge &edge:grid[node]){
            int from=node;
            int to=edge.to;
            int val=edge.val;
            if(minDist[from]!=INT_MAX&&minDist[to]>minDist[from]+val){
                minDist[to]=minDist[from]+val;
                if(!isInQueue[to]) {
                    que.push(to);
                    count[to]++;
                    if(count[to]==n){
                        fact=true;
                        while(!que.empty())que.pop();
                        break;
                    }
                }
            }
        }
    }
    if(fact)cout<<"circle"<

96. 城市间货物运输 III

最多经过k个城市,从城市A到城市B的最短路径

#include
#include
#include
using namespace std; 
//对所有边松弛n次,相当于计算起点到达与起点n条边相连的节点的最短距离
//最多经过k个城市,那么要到达与起点k+1个边相连的终点,松弛k+1次
//但是,要注意负权回路,更新minDist数组时,要看上一次松弛的from点的mindDise
int main(){
    //输入数据
    int n,m,s,t,v,src,dst,k;
    cin>>n>>m;
    vector>grid;
    for(int i=0;i>s>>t>>v;
        grid.push_back({s,t,v});
    }
    cin>>src>>dst>>k;
    //处理数据
    vectorminDist(n+1,INT_MAX);
    vectorcopy(n+1,INT_MAX);
    minDist[src]=0;
    //开始松弛
    for(int i=1;i<=k+1;i++){
        copy=minDist;
        for(vector& vec:grid){
            int from=vec[0];
            int to=vec[1];
            int val=vec[2];
            if(copy[from]!=INT_MAX&&minDist[to]>copy[from]+val){
                minDist[to]=copy[from]+val;
            }
        }
    }
    if(minDist[dst]==INT_MAX) cout<<"unreachable"<

97. 小明逛公园

Floyd算法

#include
#include
using namespace std;

int main(){
    //输入数据
    int n,m,u,v,w;
    cin>>n>>m;
    vector>>dp(n+1,vector>(n+1,vector(n+1,10005)));
    for(int i=0;i>u>>v>>w;
        dp[u][v][0]=w;
        dp[v][u][0]=w;
    }
    
    //Floyd算法
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                dp[i][j][k]=min(dp[i][j][k-1],dp[i][k][k-1]+dp[k][j][k-1]);
            }
        }
    }
    
    int q,start,end;
    cin>>q;
    while(q--){
        cin>>start>>end;
        if(dp[start][end][n]==10005) cout<<-1<

127. 骑士的攻击

#include
#include
#include
#include
using namespace std;

//A*算法   实际上是光搜的改良版
//光搜便利了太多多余的节点,可以加入一个启发式函数,引导算法向目标位置遍历
//通过对队列中的节点进行排序,让离目标最近的先出来。
//F=G+H。F是从起点到终点需要的距离。G是从起点到目前所遍历的节点经过的距离
//H是从目前节点到终点所需要的距离
//计算距离使用欧拉距离公式d=sqrt((x1-x2)^2+(y1-y2)^2)
int dir[8][2]={-2,1,-1,2,1,2,2,1,2,-1,1,-2,-1,-2,-2,-1};
int b1,b2;
int moves[1001][1001];//棋盘,同时记录路径长度

struct Knight{
    int x,y;
    int g,h,f;
    bool operator <(const Knight & k) const {
        return k.fque;
void astart(const Knight &k){
    Knight cur,next;
    que.push(k);
    while(!que.empty()){
        cur=que.top();que.pop();
        if(cur.x==b1&&cur.y==b2) break;
        for(int i=0;i<8;i++){//向八个方向遍历
            next.x=cur.x+dir[i][0];
            next.y=cur.y+dir[i][1];
            //排除掉不符合规定的情况
            if(next.x<1||next.x>1000||next.y<1||next.y>1000) continue;
            if(!moves[next.x][next.y]){
                //更新路径长度
                moves[next.x][next.y]=moves[cur.x][cur.y]+1;
                //开始计算f,g,h
                next.g=cur.g+5;//没有开根号,为了提高精度
                next.h=Heuristic(next);
                next.f=next.g+next.h;
                que.push(next);
            }
        }
    }
}

int main(){
    int n,a1,a2;
    cin>>n;
    while(n--){
        cin>>a1>>a2>>b1>>b2;
        memset(moves,0,sizeof(moves));//设置一块内存的值,
        //sizeof获取字节数
        Knight start;
        start.x=a1;
        start.y=a2;
        start.g=0;
        start.h=Heuristic(start);
        start.f=start.g+start.h;
        astart(start);
        while(!que.empty()) que.pop();
        cout<

你可能感兴趣的:(图论,深度优先,算法)