卡码网 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<