기초 도 론 문제 알고리즘 총화

그림 이론 에서 흔히 볼 수 있 는 알고리즘 의 원리 와 실현 을 소개 합 니 다. 모든 코드 가 포장 되 어 있 으 며 다운로드 할 수 있 습 니 다.
1. 인접 표 저장 도 는 인접 행렬 로 희소 도 를 표시 하면 대량의 메모리 공간 을 낭비 할 수 있다.인접 표 에 서 는 '정점 0 에서 출발 하여 정점 1, 2, 3, 4 까지' 와 같은 정 보 를 링크 에 저장 하여 그림 을 나타 낸다.이렇게 하면 O (| V | + | E |) 의 메모리 공간 만 필요 합 니 다.

  
  
  
  
  1. #include <cstdio>
  2. #include <vector>
  3. std::vector<int> g[max_v];
  4. /**
  5. *
  6. *sturct edge{
  7. * int to, cost;
  8. *};
  9. *std::vector<edge> g[max_v];
  10. */
  11. int main(void)
  12. {
  13. int v, e;
  14. scanf("%d%d", &v, &e);
  15. for(int i = 0; i != e; ++i){
  16. int s, t;
  17. scanf("%d%d", &s, &t);
  18. g[s].push_back(t);
  19. //g[t].push_back(s);//
  20. }
  21. return 0;
  22. }

2. 최 단 로 문제 1. Bellman - ford 구 단원 최 단 로 기 는 출발점 s 에서 정점 i 까지 의 최 단 거 리 는 d [i] 이 고 d [i] = min {d [j] + (j 에서 i 까지 의 가중치) | e = (j, i) 8712 ° E} 이 있 습 니 다.그림 에 동그라미 가 있 는 경우 d [s] = 0, d [i] = INF 는 제 한 된 횟수 내 에 새로운 d 를 계산 할 수 있다.s 에서 도달 할 수 있 는 음 권 이 존재 하지 않 는 다 면 | V | - 1 회 순환 후 for (;) 는 break 이 므 로 복잡 도 는 O (| V |× |E|)。즉, 마이너스 코일 이 존재 하면 제 | V | 차 순환 에서 도 d 값 이 업데이트 되 며, 이 성질 을 이용 하여 마이너스 코일 이 존재 하 는 지 확인 할 수 있다.

  
  
  
  
  1. struct edge{
  2. int from;
  3. int to;
  4. int cost;
  5. };
  6. edge es[max_e];
  7. int d[max_v];
  8. int v, e;
  9. // s
  10. void bellman_ford(int s)
  11. {
  12. for(int i = 0; i != v; ++i)
  13. d[i] = INF;//
  14. d[s] = 0;
  15. for(;;){
  16. bool update = false;
  17. for(int i = 0; i != e; ++i){
  18. edge e = es[i];
  19. if(d[e.from] != INF && d[e.to] > d[e.from] + e.cost){
  20. d[e.to] = d[e.from] + e.cost;
  21. update = true;
  22. }
  23. }
  24. if(!update)
  25. break;
  26. }
  27. }
  28. // ,
  29. bool find_negative_loop(void)
  30. {
  31. memset(d, 0, sizeof(d));
  32. for(int i = 0; i != v; ++i){
  33. for(int j = 0; j != e; ++j){
  34. edge e = es[j];
  35. if(d[e.to] > d[e.from] + e.cost){
  36. d[e.to] = d[e.from] + e.cost;
  37. // n
  38. if(i == v - 1)
  39. return true;
  40. }
  41. }
  42. }
  43. return false;
  44. }

2. Dijkstra 는 마이너스 가 없 는 단원 의 최 단 로 설명 을 구한다. ① 최 단 거리 가 확 정 된 정점 을 찾 아 이웃 정점 의 최 단 거 리 를 업데이트 한 다음 에 '최 단 거리 가 확 정 된 정점' 에 더 이상 관심 을 가 질 필요 가 없다.어떻게 '최 단 거리 가 이미 확 정 된 정점' 을 얻 습 니까?시작 할 때 출발점 까지 의 최 단 거리 만 확정 된다.아직 사용 되 지 않 은 정점 에서 d [i] 에서 가장 작은 정점 은 가장 짧 은 거리 에서 이미 확 정 된 정점 이다.다음은 시간 복잡 도 를 O (| V |²)인접 행렬 로 이 루어 진 Dijkstra 알고리즘 을 사용 합 니 다.

  
  
  
  
  1. template <typename t>
  2. inline t min(t a, t b)
  3. {
  4. return a < b ? a : b;
  5. }
  6. int cost[max_v][max_v];//
  7. int d[max_v];//
  8. bool used[max_v];//
  9. int v;//
  10. void Dijkstra(int s)
  11. {
  12. for(int i = 0; i != v; ++i)
  13. d[i] = INF;
  14. for(int i = 0; i != v; ++i)
  15. used[i] = false;
  16. d[s] = 0;
  17. for(;;){
  18. int v = -1;
  19. //
  20. for(int u = 0; u != v; ++u)
  21. if(!used[u] && (v == -1 || d[u] < d[v]))
  22. v = u;
  23. if(-1 == v)
  24. break;
  25. for(int u = 0; u != v; ++u)
  26. d[u] = min(d[u], d[v] + cost[v][u]);
  27. }
  28. }

인접 표를 사용 할 때 가장 짧 은 거 리 를 업데이트 하려 면 각 변 에 한 번 만 접근 해 야 하기 때문에 이 부분의 복잡 도 는 O (| E |) 입 니 다.그러나 정점 을 찾 으 려 면 한 번 씩 매 거 져 야 합 니 다. 결국 복잡 도 는 제곱 입 니 다. C + STL 의 우선 대기 열 priority quue 를 사용 하여 이 루어 집 니 다. 업데이트 할 때마다 현재 최 단 거리 와 정점 값 을 더미 에 삽입 합 니 다. 최소 값 이 최 단 거리 가 아니라면 버 립 니 다. 이러한 알고리즘 은 O (| E | log | V |) 로 복잡 도가 최적화 되 었 습 니 다.. Dijkstra 는 Bellman - ford 보다 효율 이 높 지만 마이너스 가 존재 하 는 그림 에 적용 할 수 없습니다.

  
  
  
  
  1. #include <queue>
  2. #include <vector>
  3. #include <utility>
  4. struct edge{
  5. int to;
  6. int cost;
  7. };
  8. typedef std::pair<int, int> P;//first , second
  9. int v;
  10. std::vector<edge> g[max_v];
  11. int d[max_v];
  12. void Dijkstra(int s)
  13. {
  14. std::priority_queue<P, std::vector<P>, std::greater<P> > que;
  15. for(int i = 0; i != v; ++i)
  16. d[i] = INF;
  17. d[s] = 0;
  18. que.push(P(0, s));
  19. while(!que.empty()){
  20. P p = que.top();
  21. que.pop();
  22. int v = p.second;
  23. if(d[v] < p.first)
  24. continue;
  25. for(unsigned int i = 0; i != g[v].size(); ++i){
  26. edge e = g[v][i];
  27. if(d[e.to] > d[v] + e.cost){
  28. d[e.to] = d[v] + e.cost;
  29. que.push(P(d[e.to], e.to));
  30. }
  31. }
  32. }
  33. }

3. 여러 그림 에서 임의의 두 점 사이 의 거 리 를 구 하 는 데 적용 되 는 Floyd - Warshall 코드 는 매우 짧 고 매우 효과 적 이 며 원 리 를 설명 하지 않 습 니 다. 마이너스 권 이 있 는 지 판단 하 는 데 도 사 용 됩 니 다. d [i] [i] 가 있 는 지 확인 하 는 것 은 마이너스 입 니 다. 복잡 도: O (| V | ^ 3).

  
  
  
  
  1. template <typename t>
  2. inline t min(t a, t b)
  3. {
  4. return a < b ? a : b;
  5. }
  6. int d[max_v][max_v];
  7. int v;
  8. void Floyd_Warshall(void)
  9. {
  10. for(int k = 0; k != v; ++k)
  11. for(int i = 0; i != v; ++i)
  12. for(int j = 0; j != v; ++j)
  13. d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
  14. }

3. 최소 생 성 트 리 문제²)。

  
  
  
  
  1. template <typename t>
  2. inline t min(t a, t b)
  3. {
  4. return a < b ? a : b;
  5. }
  6. int cost[max_v][max_v];
  7. int mincost[max_v];// X
  8. bool used[max_v] ;// i X
  9. int v;
  10. int Prim(void)
  11. {
  12. for(int i = 0; i != v; ++i){
  13. mincost[i] = INF;
  14. used[i] = false;
  15. }
  16. mincost[0] = 0;
  17. int res = 0;
  18. for(;;){
  19. int v = -1;
  20. // X X
  21. for(int u = 0; u != v; ++u)
  22. if(!used[u] && (v == -1 || mincost[u] < mincost[v]))
  23. v = u;
  24. if(-1 == v)
  25. break;
  26. used[v] = true;// v X
  27. res += mincost[v];//
  28. for(int u = 0; u != v; ++u)
  29. mincost[u] = min(mincost[u], cost[v][u]);
  30. }
  31. return res;
  32. }

2. 인접 표 에 사용 할 Kruskal 은 변 의 가중치 순 으로 작은 것 부터 큰 것 까지 한 번 봅 니 다 (정렬 필요)원 이나 무 거 운 테 두 리 를 만 들 지 않 으 면 이 테 두 리 를 생 성 트 리 에 넣 습 니 다. 원 생 성 여 부 를 어떻게 판단 합 니까? u 와 v 를 연결 하 는 테 두 리 를 생 성 트 리 에 넣 으 려 면 그 전에 u 와 v 가 같은 연결 분량 에 있 지 않 으 면 e 를 넣 으 면 원 이 생기 지 않 습 니 다. 있 으 면 반드시 원 이 생 성 됩 니 다. 집합 을 도입 하고 찾 으 면 됩 니 다. 그리고 그 실현 은 코드 팩 에 포함 되 어 있 습 니 다. Kruskal가장 오래 걸 리 는 동작 은 변 에 대한 정렬 입 니 다. 시간 복잡 도: O (| E | log | V |).

  
  
  
  
  1. #include <algorithm>
  2. #include "Union_Find.cpp"
  3. struct edge{
  4. int u, v, cost;
  5. };
  6. bool comp(const edge &a, const edge &b)
  7. {
  8. return a.cost < b.cost;
  9. }
  10. edge es[max_e];
  11. int v, e;
  12. int Kruskal(void)
  13. {
  14. std::sort(es, es + e, comp);
  15. init(v);//
  16. int res = 0;
  17. for(int i = 0; i != e; ++i){
  18. edge e = es[i];
  19. if(!same(e.u, e.v)){
  20. unite(e.u, e.v);
  21. res += e.cost;
  22. }
  23. }
  24. return res;
  25. }

좋은 웹페이지 즐겨찾기