文章目录

  • 0 模板
    • 邻接矩阵 模板
    • 邻接表 模板
  • 1 图的遍历
    • 1.1 邻接矩阵/邻接表 + dfs/bfs
      • 1013(25:邻接矩阵 + 求连通分量数 + dfs)
      • 1021(25:邻接表 + 求连通分量数 + 每个顶点作为根节点的树的深度 + dfs)
      • 1034(30:hash + 求带权图的每个连通分量的最大点权重和总权重 + dfs)
      • 1076(30:求单源点到每个顶点的层数 + bfs)
    • 1.2 图论
      • 1091(30:三维数组 + bfs)
      • 1122(25:根据路径,判断环)
      • 1150(25:根据路径,判断环)
      • 1126(25:顶点的度+判断连通图)
      • 1142(1142:判断最大点集,任意两个点相连)
  • 2 最短路径
    • 2.1 Dijkstra
      • 模板
        • dijkstra() 模板
        • dfs() 模板
      • 1003(25:多条最短路径 + dfs点权重)
      • 1018(30:多条最短路径 + dfs)
      • 1030(30:多条最短路径 + dfs边权重)
  • 拓扑排序
    • 1146(25:判断序列是否为拓扑排序 + 顶点的入度)

0 模板

邻接矩阵:(一般)

  • 当N<1000
  • 带权图
  • 插删边 / 顶点

邻接表:

  • 当N很大
  • 题目明确说了,是稀疏图

邻接矩阵 模板

#include<cstdio>
#include<algorithm>using namespace std;const int N=1000+10;int gra[N][N];       //邻接矩阵(1 or 0)或(data or INF)
bool visit[N];
int n;void dfs(int v){  ...//visit[v] = true;for(int i=1; i<=n; i++){if(visit[i]==false && gra[v][i]==1){dfs(i);}}
}void bfs(int v){queue<int> Q;Q.push(v);visit[v] = true;while(!Q.empty()){int f = Q.front();Q.pop();for(int i=1; i<=n; i++){if(visit[i]==false && gra[f][i]==1){Q.push(i);visit[i] = true;}}}
}int main(){//freopen("in.txt", "r", stdin);fill(gra[0], gra[0]+N*N, 0);// fill(gra[0], gra[0] +N*N, INF);fill(visit, visit+N, false);//dfsint cnt=0;   //连通分量的个数for(int i=1; i<=n; i++){if(visit[i]==false){dfs(i);       cnt++;}}// bfsint cnt=0; //连通分量的个数for(int i=1; i<=n; i++){if(visit[i]==false){bfs(i);       cnt++;}}//fclose(stdin);return 0;
}

邻接表 模板

#include<cstdio>
#include<vector>
#include<algorithm>using namespace std;const int N=10000+10;vector<vector<int> > gra;
// the nodes are numbered from 1 to n
// 否则:vector<int> gra[N];
int visit[N];void dfs(int v){   ...//visit[v] = true;for(int i=0; i<gra[v].size(); i++){int k = gra[v][i];if(visit[gra[v][i]]==false){dfs(gra[v][i]);}}
}int main(){freopen("in.txt", "r", stdin);gra.resize(n+1); //从1~nfill(visit, visit+N, false);....gra[a].push_back(b);     //无向图gra[b].push_back(a);...//int cnt=0;   //连通分量数for(int i=1; i<=n; i++){if(visit[i]==false){    //以i为顶点,遍历所有其它顶点(它能到达的)dfs(i,1);   cnt++;}}fclose(stdin);return 0;
}

1 图的遍历

1.1 邻接矩阵/邻接表 + dfs/bfs

1013(25:邻接矩阵 + 求连通分量数 + dfs)

(1)题目
求最少添加几条边使图连通(= 连通分量数 - 1)

(2)代码

#include<cstdio>
#include<vector>
#include<algorithm>
#include<set>using namespace std;const int N=1000+10;int gra[N][N];     //邻接矩阵(1 or 0)
bool visit[N];
int n;void dfs(int v){  //visit[v] = true;for(int i=1; i<=n; i++){if(visit[i]==false && gra[v][i]==1){dfs(i);}}
}int main(){//freopen("in.txt", "r", stdin);int m,k;scanf("%d%d%d",&n, &m, &k);fill(gra[0], gra[0]+N*N, 0);for(int i=0; i<m; i++){int a,b;scanf("%d%d", &a, &b);gra[a][b]=1;        //无向图gra[b][a]=1;}//for(int i=0; i<k; i++){fill(visit, visit+N, false);int v;scanf("%d", &v);// 去除顶点v,就是标记为访问过visit[v] = true;//int cnt=0;//连通分量数for(int i=1; i<=n; i++){if(visit[i]==false){dfs(i);        cnt++;}}printf("%d\n", cnt-1);}//fclose(stdin);return 0;
}

(3)小结

  • 使图连通时,最少添加边数 = 连通分量数 - 1
  • 若删除边、顶点,用邻接矩阵
  • 删除顶点:标记为访问过
    visit[v] = true;
  • fill 二维数组
int a[N][N];
fill(a[0], a[0] + N*N, 0);
// 不是 fill(a, a + N*N, 0);

1021(25:邻接表 + 求连通分量数 + 每个顶点作为根节点的树的深度 + dfs)

(1)题目
求连通分量数 + 每个顶点作为根节点的树的深度
(2)代码

#include<cstdio>
#include<vector>
#include<algorithm>
#include<set>using namespace std;const int N=10000+10;vector<vector<int> > gra;
// the nodes are numbered from 1 to n
// 否则:vector<int> gra[N];
int visit[N];int depth[N];  //顶点i的深度int temp_depth;     //当前顶点作为根的深度
void dfs(int v, int level){ if(level > temp_depth){temp_depth = level;}//visit[v] = true;for(int i=0; i<gra[v].size(); i++){int k = gra[v][i];if(visit[gra[v][i]]==false){dfs(gra[v][i], level+1);}}
}int main(){//freopen("in.txt", "r", stdin);int n;scanf("%d",&n);gra.resize(n+1);    //从1~nfill(visit, visit+N, false);for(int i=0; i<n-1; i++){int a,b;scanf("%d%d", &a, &b);gra[a].push_back(b);      //无向图gra[b].push_back(a);}//int cnt=0; //连通分量数for(int i=1; i<=n; i++){if(visit[i]==false){dfs(i,1);   //i为根节点cnt++;}}if(cnt>=2) printf("Error: %d components",cnt);else{//每个节点作为根节点,都遍历一遍for(int i=1; i<=n; i++){fill(visit, visit+N, false);temp_depth=0;dfs(i,1);   depth[i] = temp_depth;}//int max_high=0;set<int> st;for(int i=1; i<=n; i++){if(depth[i] > max_high){st.clear();st.insert(i);max_high = depth[i];}else if(depth[i]==max_high){st.insert(i);}}set<int>::iterator it = st.begin();for(; it!=st.end(); it++){printf("%d\n", *it);}}//fclose(stdin);return 0;
}

1034(30:hash + 求带权图的每个连通分量的最大点权重和总权重 + dfs)

(1)题目
hash + 求带权图的每个连通分量的最大点权重和总权重

(2)代码

#include<cstdio>
#include<algorithm>
#include<map>
#include<string>
#include<iostream>
#include<set>using namespace std;const int INF=0x3f3f3f3f;
const int N=2000+10;int gra[N][N];        //邻接矩阵(data or INF)
bool visit[N];
int n;
int weight[N];      //顶点的权重
map<string, int> mp_head; //存储最终的所有head,按name排序map<int , string> mp_itos;        //得到string
map<string, int> mp_stoi;     //得到int
int nameNum=1;int string_to_int(string &str){if(mp_stoi.find(str)==mp_stoi.end()){mp_stoi[str] = nameNum;mp_itos[nameNum] = str;nameNum++;}return mp_stoi[str];
}int gangNum;   //每个连通分量的顶点数
int total;      //每个连通分量的总权重
int head;       //每个连通分量的head
void dfs(int v){    //visit[v] = true;gangNum++;if(weight[v] > weight[head]){head = v;}for(int i=1; i<nameNum; i++){if(gra[v][i]!=INF){total += gra[v][i];if(visit[i]==false) {dfs(i);}           }}
}int main(){//freopen("in.txt", "r", stdin);int k;scanf("%d%d",&n, &k);fill(gra[0], gra[0]+N*N, INF);fill(weight, weight+N, 0);for(int i=0; i<n; i++){string s1,s2;   cin>>s1>>s2;int id1 = string_to_int(s1);int id2 = string_to_int(s2);int t;scanf("%d", &t);// 有向图gra[id1][id2] = t;weight[id1] += t;weight[id2] += t;}fill(visit, visit+N, false);//for(int i=1; i<nameNum; i++){        //顶点:1~nameNum-1if(visit[i]==false){total = 0;head = i;gangNum = 0;dfs(i);if(gangNum>2 && total>k){string name = mp_itos[head];mp_head[name] =  gangNum;}}      }printf("%d\n", mp_head.size());map<string, int>::iterator it;for(it = mp_head.begin(); it!=mp_head.end(); it++){printf("%s %d\n", it->first.c_str(), it->second);}//fclose(stdin);return 0;
}

(3)小结

  • 此题,hash存储字符串用的是map,字符串对应的id:从1到nameNum-1
map<int , string> mp_itos;     //得到string
map<string, int> mp_stoi;     //得到int
int nameNum=1;
  • map查找
    if(mp.find(key) != mp.end()){

    }

  • 段错误

    (1)一个或两个测试点 段错误: N小了,数组要开大点
    (2)多个测试点 段错误:写的代码数组越界

    陷进,N到底为多大(最多顶点数),题目说 的是边最多1000条,N应该至少2000

1076(30:求单源点到每个顶点的层数 + bfs)

(1)

(2)

#include<cstdio>
#include<algorithm>
#include<queue>using namespace std;const int N=1000+10;int gra[N][N];       //邻接矩阵(1 or 0)
bool visit[N];
int n;int L;
int level_id[N];    //每个节点的层数int bfs(int v){queue<int> Q;Q.push(v);visit[v] = true;int cnt=0;while(!Q.empty()){int f = Q.front();Q.pop();for(int i=1; i<=n; i++){if(visit[i]==false && gra[f][i]==1 && level_id[f]+1<=L){level_id[i] =  level_id[f]+1;Q.push(i);visit[i] = true;cnt++;}}}return cnt;
}int main(){//freopen("in.txt", "r", stdin);scanf("%d%d",&n, &L);fill(gra[0], gra[0]+N*N, 0);for(int i=1; i<=n; i++){int t;scanf("%d", &t);for(int j=0; j<t; j++){int a;scanf("%d", &a);gra[a][i] = 1; // 有向图}}int k;scanf("%d", &k);for(int i=0; i<k; i++){int id;scanf("%d", &id);fill(visit, visit+N, false);fill(level_id, level_id+N, -1);level_id[id] = 0;printf("%d\n", bfs(id));}//fclose(stdin);return 0;
}

(3)小结

  • 根据遍历方向,设计边的方向
    如, a fallows b,
    gra[a][b]=1 ? or gra[b][a]=1 ?
    对于b来说,求所有不超过L层的间接粉丝转发他微博的人数,即求所有其他节点到b的层数,因此,为了便于遍历,要逆向思维,把b作为根节点,求它到其他节点的层数
    存gra[b][a] = 1

1.2 图论

1091(30:三维数组 + bfs)

(2)代码

#include<cstdio>
#include<algorithm>
#include<queue>using namespace std;int gra[1300][130][70];        // 70个二维:1300*130
bool visit[1300][130][70];
int m, n, L, T;typedef struct Node{int x,y,z;
}Node;int X[6] = {1,-1,0,0,0,0};
int Y[6] = {0,0,1,-1,0,0};
int Z[6] = {0,0,0,0,1,-1};//判断是否出边界
bool isIn(int x, int y, int z){if(x>=0 && x<m && y>=0 && y<n && z>=0 && z<L) return true;return false;
}int bfs(int x, int y, int z){Node node = {x,y,z};queue<Node> Q;Q.push(node);visit[x][y][z] = true;int cnt=0;while(!Q.empty()){Node f = Q.front();Q.pop();cnt++;//6个方向遍历    for(int i=0; i<6; i++){int tx = f.x + X[i];int ty = f.y + Y[i];int tz = f.z + Z[i];if(isIn(tx,ty,tz) && visit[tx][ty][tz]==false && gra[tx][ty][tz]==1){Node node_t = {tx, ty,tz};Q.push(node_t);visit[tx][ty][tz]=true;}}}if(cnt<T) cnt=0;return cnt;
}int main(){//freopen("in.txt", "r", stdin);scanf("%d%d%d%d",&m, &n, &L, &T);for(int i=0; i<L; i++){for(int j=0; j<m; j++){for(int k=0; k<n; k++){int t;scanf("%d", &t);gra[j][k][i] = t;}}}fill(visit[0][0], visit[0][0]+1300*130*70, false);//int num=0;for(int i=0; i<L; i++){for(int j=0; j<m; j++){for(int k=0; k<n; k++){if(visit[j][k][i] == false && gra[j][k][i]==1){num += bfs(j,k,i);}}}}printf("%d", num);//fclose(stdin);return 0;
}

(3)小结

  • 顶点太多,用dfs递归内存会爆,因此用bfs
  • 如果运行没有输出 或 评测结果为内存超限
    则:bfs或dfs没有正确结束
  • dfs / bfs中找到邻接点后,至少有2个判断
for(...)if(visit[.]==false && gra[.][.]==1)// or if(visit[.]==false && gra[.][.]!=INF)

1122(25:根据路径,判断环)

(1)

(2)代码

#include<cstdio>
#include<algorithm>
#include<vector>using namespace std;const int N =300; int gra[N][N];
int visit[N];       //统计访问几次
int n;vector<int> vect;int main(){//freopen("in.txt", "r", stdin);fill(gra[0], gra[0]+N*N, 0);int m;scanf("%d%d", &n, &m);for(int i=0; i<m; i++){int a,b;scanf("%d%d", &a, &b);gra[a][b] = gra[b][a]=1;}//int k;scanf("%d", &k);for(int i=0; i<k; i++){int t;scanf("%d", &t);vect.resize(t);for(int j=0; j<t; j++){scanf("%d", &vect[j]);}//fill(visit, visit+N, 0);int flag=0;      //输出YESfor(int j=0; j<vect.size(); j++){int v1 = vect[j];if(j==vect.size()-1){visit[v1] ++;}else{int v2 = vect[j+1];visit[v1] ++;if(gra[v1][v2]==0){flag=1;       //走不通break;}    if(visit[v1]==2) break;}              }if(flag==1) printf("NO\n");else{// 所有顶点visit[v]除了一个=2外,其余=1int cnt=0;for(int j=1; j<=n; j++){if(visit[j]==1) {continue;}if(visit[j]==2){                  cnt++;continue;}flag=1;break;}if(cnt==1 && flag==0 && vect[0]==vect[vect.size()-1]){printf("YES\n");}else{printf("NO\n");}}        vect.clear();}//fclose(stdin);return 0;
}

(3)小结

  • 明确什么情况输出 YES:(以下都满足)
    1.走得通
    2.头尾顶点相同
    3.visit[头顶点]=2,其余顶点=1

1150(25:根据路径,判断环)

(2)代码

#include<cstdio>
#include<algorithm>
#include<vector>const int INF=0x3f3f3f3f;
using namespace std;const int N =300; int gra[N][N];
int visit[N];       //统计访问几次
int n;vector<int> vect;int main(){//freopen("in.txt", "r", stdin);fill(gra[0], gra[0]+N*N, INF);int m;scanf("%d%d", &n, &m);for(int i=0; i<m; i++){int a,b,dis;scanf("%d%d%d", &a, &b, &dis);gra[a][b] = gra[b][a]=dis;}//int best_path;int best_dist=INF;      //!!!int k;scanf("%d", &k);for(int p=1; p<=k; p++){fill(visit, visit+N, 0);int len;scanf("%d", &len);for(int i=0; i<len; i++){int t;scanf("%d", &t);vect.push_back(t);}//int flag=0;int dist=0;for(int i=0; i<vect.size(); i++){int v1 = vect[i];visit[v1]++;if(i!=vect.size()-1){int v2 = vect[i+1];if(gra[v1][v2]==INF){flag=1; dist=INF;break;}else{dist += gra[v1][v2];}}}int flag2=0;for(int i=1; i<=n; i++){if(visit[i]==0){flag=1;break;}if(i!=vect[0] && visit[i]!=1){flag2=1;break;}}if(vect[0]!=vect[vect.size()-1] || flag==1){if(dist!=INF){printf("Path %d: %d (Not a TS cycle)\n",p, dist);}else{printf("Path %d: NA (Not a TS cycle)\n",p);}}else{if(visit[vect[0]]==2 && flag2==0){printf("Path %d: %d (TS simple cycle)\n",p, dist);               }else{printf("Path %d: %d (TS cycle)\n",p, dist);}    if(dist<best_dist){best_path = p;best_dist = dist;}}vect.clear();}printf("Shortest Dist(%d) = %d", best_path, best_dist);//fclose(stdin);return 0;
}

(3)小结

  • 明确各种情况
    (1)Not a TS cycle:(以下满足一个)
    1.不通
    2.存在visit[v]=0
    3.头!=尾顶点
    (2)TS simple cycle:
    1.只有visit[头顶点]=2,其余=1
    (3)Not a TS cycle
    其余

1126(25:顶点的度+判断连通图)

(2)代码

#include<cstdio>
#include<algorithm>using namespace std;const int N =600; int gra[N][N];
bool visit[N];      //统计访问几次
int n;int degree[N];        //顶点的度数void dfs(int v){visit[v] = true;for(int i=1; i<=n; i++){if(visit[i]==false && gra[v][i]==1){dfs(i);}}
}int main(){//freopen("in.txt", "r", stdin);fill(gra[0], gra[0]+N*N, 0);int m;scanf("%d%d", &n, &m);for(int i=0; i<m; i++){int a,b;scanf("%d%d", &a, &b);gra[a][b] = gra[b][a]=1;}//int even_num=0, odd_num=0;for(int i=1; i<=n; i++){if(i!=1) printf(" ");int deg=0;for(int j=0; j<=n; j++){if(gra[i][j]==1){deg++;}}if(deg%2==0) even_num++;else odd_num++;degree[i] = deg;printf("%d", degree[i]);}printf("\n");//int cnt=0;    //判断是不是连通图fill(visit, visit+N, false);for(int i=1; i<=n; i++){if(visit[i]==false){dfs(i);cnt++;}}//if(cnt==1){if(even_num==n){      //所有顶点度数都为偶printf("Eulerian");}else if(odd_num==2){ //只有2个顶点度数为奇printf("Semi-Eulerian");}else{printf("Non-Eulerian");}}else{printf("Non-Eulerian");}//fclose(stdin);return 0;
}

(3)小结

  • 看懂题目,不是要你证明(根据Eulerian path证明Eulerian),而是要你根据顶点的度判断是不是Eulerian

1142(1142:判断最大点集,任意两个点相连)

(2)代码

#include<cstdio>
#include<algorithm>
#include<vector>using namespace std;const int N =300; int gra[N][N];
int visit[N];       //统计访问几次
int n;vector<int> vect;bool isClique(){for(int i=0; i<vect.size(); i++){for(int j=i+1; j<vect.size(); j++){if(gra[vect[i]][vect[j]]==0) return false;}}return true;
}int main(){//freopen("in.txt", "r", stdin);fill(gra[0], gra[0]+N*N, 0);int ne;scanf("%d%d", &n, &ne);for(int i=0; i<ne; i++){int a,b;scanf("%d%d", &a, &b);gra[a][b] = gra[b][a]=1;}//int m;scanf("%d", &m);for(int i=0; i<m; i++){fill(visit, visit+N, false);int k;scanf("%d", &k);vect.resize(k);for(int j=0; j<k; j++){scanf("%d", &vect[j]);visit[vect[j]] = true;}//if(!isClique()){printf("Not a Clique\n");}else{int flag=0;for(int i=1; i<=n; i++){if(visit[i]==false){vect.push_back(i);if(isClique()){flag=1;break;}vect.pop_back();}}if(flag==0) printf("Yes\n");else printf("Not Maximal\n");}vect.clear();}//fclose(stdin);return 0;
}

(3)小结

  • 完全图:
    有向:m = n*(n-1)
    无向:m = n*(n-1)/2
  • adjacent.:指v1和v2有边,而不是有路径

2 最短路径

2.1 Dijkstra

模板

  • 变量
int D[N];        初始化:=INF        开始结点v =0
int path[N];           =-1             =-1
vector<int> path[N];  \               \
int PNUM[N];           =0              =1
int W[N];              =0              =weight[v]
  • 步骤
    第一步:写dijkstra():只求D[]和path[]
    第二步:多条路径选1条,用dfs()从目的点开始,倒求,难点
  • dijkstra()模板:顶点下标遍历,共4个for要修改

dijkstra() 模板

(1)求最短路径(1条)

int D[N];        //v到各个顶点的距离
int path[N];    //path[i]为i的前驱//n个顶点,为0~n-1(一共4个for要修改)
void dijkstra(int v){fill(visit, visit+N, false);      //易遗漏!!!fill(D, D+N, INF);fill(path, path+N, -1);for(int i=0; i<n; i++){if(gra[v][i]!=INF){D[i] = gra[v][i];}}D[v] = 0;     //!!!path[v] = -1;for(int k=0; k<n; k++){        int u=-1, min = INF;      //到当前顶点的最短距离for(int i=0; i<n; i++){   //在D[]中选择一条最短路径if(visit[i]==false && D[i]<min){u = i;min = D[i];}}if(u==-1) break;visit[u] = true;for(int i=0; i<n; i++){   // 更新其余顶点if(visit[i]==false && gra[u][i]!=INF){if(D[u]+gra[u][i] < D[i]) {       // 1条最短路径(走i更短)D[i] =  D[u]+gra[u][i];path[i] = u;}}}}
}

(2)多条最短路径

int D[N];        //v到各个顶点的距离
vector<int> path[N];  //n个顶点,为0~n-1(一共4个for要修改)
void dijkstra(int v){fill(visit, visit+N, false);fill(D, D+N, INF);for(int i=0; i<n; i++){if(gra[v][i]!=INF){D[i] = gra[v][i];}}D[v] = 0;        //!!!for(int k=0; k<n; k++){      int u=-1, min = INF;      //到当前顶点的最短距离for(int i=0; i<n; i++){   //在D[]中选择一条最短路径if(visit[i]==false && D[i]<min){u = i;min = D[i];}}if(u==-1) break;visit[u] = true;for(int i=0; i<n; i++){   // 更新其余顶点if(visit[i]==false && gra[u][i]!=INF){if(D[u]+gra[u][i] < D[i]) {       // 1条最短路径(走i更短)D[i] =  D[u]+gra[u][i];path[i].clear();path[i].push_back(u);}else if(D[u]+gra[u][i] == D[i]){ //多条最短路径(走i和走u一样)path[i].push_back(u);}}}}
}

dfs() 模板

vector<int> bestPath, tempPath; //【倒存】:最后一个为 源点
int cntPath=0;     //最短路径条数void dfs(int v, int s){     //s为开始点tempPath.push_back(v);if(v==s){        //边界cntPath++;...tempPath.pop_back();return;}for(int i=0; i<path[v].size(); i++){dfs(path[v][i], s);}tempPath.pop_back();
}

1003(25:多条最短路径 + dfs点权重)

(2)代码

#include<cstdio>
#include<algorithm>
#include<vector>using namespace std;const int INF=0x3f3f3f3f;
const int N =600; int gra[N][N];
bool visit[N];
int n;
int weight[N];      //顶点权重int D[N];     //v到各个顶点的距离
vector<int> path[N];  void dijkstra(int v){fill(visit, visit+N, false);fill(D, D+N, INF);for(int i=0; i<n; i++){if(gra[v][i]!=INF){D[i] = gra[v][i];}}D[v] = 0;        //!!!for(int i=0; i<n; i++){      int u=-1, min = INF;      //到当前顶点的最短距离for(int i=0; i<n; i++){   //在D[]中选择一条最短路径if(visit[i]==false && D[i]<min){u = i;min = D[i];}}if(u==-1) break;visit[u] = true;for(int i=0; i<n; i++){   // 更新其余顶点if(visit[i]==false && gra[u][i]!=INF){if(D[u]+gra[u][i] < D[i]) {       // 1条最短路径(走i更短)D[i] =  D[u]+gra[u][i];path[i].clear();path[i].push_back(u);}else if(D[u]+gra[u][i] == D[i]){ //多条最短路径(走i和走u一样)path[i].push_back(u);}}}}
}vector<int> bestPath, tempPath; //【倒存】:最后一个为 源点
int cntPath=0;
int maxWeight = -1;void dfs(int v, int s){     //s为开始点tempPath.push_back(v);if(v==s){        //边界cntPath++;int sum=0;for(int i=tempPath.size()-1; i>=0; i--){int u =  tempPath[i];sum += weight[u];}if(sum > maxWeight){maxWeight = sum;bestPath = tempPath;}tempPath.pop_back();return;}for(int i=0; i<path[v].size(); i++){dfs(path[v][i], s);}tempPath.pop_back();
}int main(){//freopen("in.txt", "r", stdin);fill(gra[0], gra[0]+N*N, INF);int m, c1, c2;scanf("%d%d%d%d", &n, &m, &c1, &c2);for(int i=0; i<n; i++){scanf("%d", &weight[i]);}for(int i=0; i<m; i++){int a,b,dist;scanf("%d%d%d", &a, &b, &dist);gra[a][b] = gra[b][a]=dist;}//dijkstra(c1);//dfs(c2, c1);//printf("%d %d", cntPath, maxWeight);//fclose(stdin);return 0;
}

1018(30:多条最短路径 + dfs)

(2)代码

#include<cstdio>
#include<algorithm>
#include<vector>using namespace std;const int INF=0x3f3f3f3f;
const int N =600; int gra[N][N];
bool visit[N];
int n;
int weight[N];      //顶点权重int CMAX;
int D[N];       //v到各个顶点的距离
vector<int> path[N];  void dijkstra(int v){fill(D, D+N, INF);for(int i=0; i<=n; i++){if(gra[v][i]!=INF){D[i] = gra[v][i];}}D[v] = 0;       //!!!for(int i=0; i<=n; i++){        //n+1个顶点int u=-1, min = INF;     //到当前顶点的最短距离for(int i=0; i<=n; i++){ //在D[]中选择一条最短路径if(visit[i]==false && D[i]<min){u = i;min = D[i];}}if(u==-1) break;visit[u] = true;for(int i=0; i<=n; i++){ // 更新其余顶点if(visit[i]==false && gra[u][i]!=INF){if(D[u]+gra[u][i] < D[i]) {       // 1条最短路径(走i更短)D[i] =  D[u]+gra[u][i];path[i].clear();path[i].push_back(u);}else if(D[u]+gra[u][i] == D[i]){ //多条最短路径(走i和走u一样)path[i].push_back(u);}}}}
}int bestPath[N];
int minSend, minBack;void dfs(int v, int sumSend){if(v==0){}for(int i=0; i<path[v].size(); i++){int u = path[v][i];dfs(u,sumSend+weight[u]);  //v的前序}
}int main(){freopen("in.txt", "r", stdin);fill(gra[0], gra[0]+N*N, INF);int sp,m;scanf("%d%d%d%d", &CMAX, &n, &sp, &m);for(int i=1; i<=n; i++){scanf("%d", &weight[i]);weight[i] =  weight[i] - CMAX/2;    //除了自身perfect外,剩余的(可能为负)}for(int i=0; i<m; i++){int a,b,dist;scanf("%d%d%d", &a, &b, &dist);gra[a][b] = gra[b][a]=dist;}//dijkstra(0);// 调整fclose(stdin);return 0;
}

(3)小结

  • dfs调整,从目的地sp开始,不是从根节点开始,逆向思维,倒着dfs

1030(30:多条最短路径 + dfs边权重)

(2)代码

#include<cstdio>
#include<algorithm>
#include<vector>using namespace std;const int INF=0x3f3f3f3f;
const int N =600; int gra[N][N];
bool visit[N];
int n;
int cost[N][N];     //边权重int D[N];      //v到各个顶点的距离//n个顶点,为0~n-1(一共4个for要修改)
void dijkstra(int v){fill(visit, visit+N, false);fill(D, D+N, INF);for(int i=0; i<n; i++){if(gra[v][i]!=INF){D[i] = gra[v][i];}}D[v] = 0;        //!!!for(int i=0; i<n; i++){      int u=-1, min = INF;      //到当前顶点的最短距离for(int i=0; i<n; i++){   //在D[]中选择一条最短路径if(visit[i]==false && D[i]<min){u = i;min = D[i];}}if(u==-1) break;visit[u] = true;for(int i=0; i<n; i++){   // 更新其余顶点if(visit[i]==false && gra[u][i]!=INF){if(D[u]+gra[u][i] < D[i]) {       // 1条最短路径(走i更短)D[i] =  D[u]+gra[u][i];path[i].clear();path[i].push_back(u);}else if(D[u]+gra[u][i] == D[i]){ //多条最短路径(走i和走u一样)path[i].push_back(u);}}}}
}vector<int> bestPath, tempPath; //倒存:目的地,..,源点
int minCost = INF;void dfs(int v, int s){      //s为开始点tempPath.push_back(v);if(v==s){        //边界//求tempPath上的costint sum=0;for(int i=tempPath.size()-1; i>0; i--){int u = tempPath[i];int pre = tempPath[i-1];sum += cost[pre][u];}// 检查cost是否最小if(sum < minCost){minCost = sum;bestPath = tempPath;}tempPath.pop_back();return;}for(int i=0; i<path[v].size(); i++){dfs(path[v][i], s);}tempPath.pop_back();
}int main(){//freopen("in.txt", "r", stdin);fill(gra[0], gra[0]+N*N, INF);int m, v1, v2;scanf("%d%d%d%d", &n, &m, &v1, &v2);for(int i=0; i<m; i++){int a,b,dist,c;scanf("%d%d%d%d", &a, &b, &dist, &c);gra[a][b] = gra[b][a]=dist;cost[a][b] = cost[b][a] = c;}//dijkstra(v1);// dfs(v2, v1);//for(int i=bestPath.size()-1; i>=0; i--){printf("%d ", bestPath[i]);}printf("%d %d", D[v2], minCost);//fclose(stdin);return 0;
}

拓扑排序

  • 有向图G,是否存在拓扑排序?
    存在: 则无环,进行拓扑排序
    不存在,有环
  • 对有向无环图进行拓扑排序:所有顶点的序列(可有多个序列)
    系列中:所有顶点出现 且 仅1次; V1在V2的前面,则v1到V2必有路径

1146(25:判断序列是否为拓扑排序 + 顶点的入度)

顶点v:
(1)viisit[v] ==0
(2)入度 ==0
满足条件,则删除gra[v][i]的边,visit[v]
结束时:
所有顶点visit[]=1

PAT之图:遍历、最短路径dijkstra相关推荐

  1. python棋盘最短路径_Python数据结构与算法之图的最短路径(Dijkstra算法)完整实例...

    本文实例讲述了Python数据结构与算法之图的最短路径(Dijkstra算法).分享给大家供大家参考,具体如下: # coding:utf-8 # Dijkstra算法--通过边实现松弛 # 指定一个 ...

  2. c++ 遍历所有点且距离最短_C/C++ 图的最短路径 Dijkstra 算法

    作者:小石王 链接:https://www.cnblogs.com/xiaoshiwang/p/9442391.html 图的最短路径的概念: 一位旅客要从城市A到城市B,他希望选择一条途中中转次数最 ...

  3. 【数据结构】图(最短路径Dijkstra算法)的JAVA代码实现

    最短路径的概念 最短路径的问题是比较典型的应用问题.在图中,确定了起始点和终点之后,一般情况下都可以有很多条路径来连接两者.而边或弧的权值最小的那一条路径就称为两点之间的最短路径,路径上的第一个顶点为 ...

  4. 三牛三虎过河问题--图的最短路径dijkstra算法--简单的Python实现

    问题:三头牛三只虎要过河,船需要一只动物来划,另外至多还能载一物,而只有一头牛和一只虎会划船,并且当虎的数量多于牛的数量时,虎要吃牛,请设计一个安全渡河方案,并使渡河次数尽量少. 我们用一个数组来表示 ...

  5. 图的最短路径dijkstra算法

    想法是这样的: 1. 最开始要建立4个list,分别存储 a. 所有的Vertex: allVertex[] b. 一个空的Vertex list: emptyVertex[] c. 一个前缀表 pr ...

  6. 图的最短路径--单源、多源最短路径

    最短路径 –在网络中,求两个不同顶点之间的所有路径中,边的权值之和最小的路劲. 单源最短路径 –从某固定源点出发的最短路径 无权图的最短路径 按照路径长度递增的顺序找出源点到各个顶点的最短路径 类似于 ...

  7. 图的最短路径算法及matlab实现(Dijkstra算法、Floyd算法、Bellman-Ford算法、Johnson 算法)

    图的最短路径算法 Dijkstra算法 Dijkstra算法研究的是从初始点到其他任一结点的最短路径,即单源最短路径问题,其对图的要求是不存在负权值的边. Dijkstra算法主要特点是以起始点为中心 ...

  8. Dijkstra算法求解图中最短路径距离

    前言:这里是自学内容,讲解的是用python来实现Dijkstra算法,算是入门求解图中最短路径问题的典型案例. 算法简介: 迪杰斯特拉(Dijkstra)算法是一个按照路径长度递增的次序产生的最短路 ...

  9. 带权图的最短路径算法(Dijkstra)实现

    一,介绍 本文实现带权图的最短路径算法.给定图中一个顶点,求解该顶点到图中所有其他顶点的最短路径 以及 最短路径的长度.在决定写这篇文章之前,在网上找了很多关于Dijkstra算法实现,但大部分是不带 ...

  10. 网状结构(图)图的存储(邻接矩阵、邻接表)、图的遍历(深度DFS、广度BFS)、图的最短路径

    图 多对多关系 是一种网状数据结构,图是由非空的顶点集合和一个描述顶点之间关系的集合组成 其定义 Graph = (V, E) V={x | x ∈某个数据对象} E = {<u, v> ...

最新文章

  1. java二个整数相减_Java-消息框显示两整数加减乘除
  2. python代码检测链表中的环并删除环
  3. js判断数组中对象是否存在某个值
  4. 巴比伦算法求平方根c语言,巴比伦算法求平方根
  5. python求和_Python程序查找特殊求和系列的解决方案
  6. python读取文件夹下所有文件的名称_python2.7 学习之读取文件夹下所有文件名称及内容...
  7. 关于28379D的X-BAR
  8. 【随笔】蒟蒻的告别?
  9. ubuntu20禁止hdmi显示器音频输出
  10. 获取input输入值和获取form表单中的组件输入值区别
  11. 银河麒麟系统开启root用户登录
  12. 医学影像分割论文合集
  13. 计算机研究生学什么课本,计算机研究生到底该怎么读?
  14. 创建电脑对象,电脑对象有关机和开机方法(静态对象构造方法)
  15. python通过经纬度获取地址信息
  16. 覆盖所有面试知识点,已拿到offer
  17. 利达主机联网接线端子_利达接线图介绍
  18. 【Mixup】《Mixup:Beyond Empirical Risk Minimization》
  19. 告别传统开店模式,借鉴餐饮理发店经营思路,谁都可以当甩手掌柜
  20. Java面试题-Java基础-并发编程

热门文章

  1. 怎样提高java平台的性能
  2. 替代top的系统监控工具glances
  3. 23种设计模式(6):模版方法模式
  4. 用python调用ICTCLAS50进行中文分词
  5. ZOJ 1010. Area 解题报告
  6. python set集合与列表_python set集合的添加、删除、修改和访问操作/frozenset 集合,集合内置方法完整列表-立地货...
  7. logback.xml日志配置文件,springboot
  8. jpadao层继承什么_1岁英短蓝白母猫能卖多少钱,银渐层2岁公猫多少钱
  9. android 的接口回调,android 接口 接口回调
  10. 2 VUE.js 内部指令