2019-11-02  本文已影响0人  雨落夏至

求解最短路径

时间复杂度 空间复杂度

多源最长路径(DAG)(关键路径)
深度遍历
  void dfs(int cur,int dst){
        if(minpath<dst) return;//当前走过的路径大雨之前的最短路径,没有必要再走下去了
        if(cur==en){//临界条件,当走到终点n
           if(minpath>dst){ minpath=dst; return;  }
        }
        for(int i=1;i<=n;i++){
            if(mark[i]==0&&edge[cur][i]!=inf&&edge[cur][i]!=0){
                mark[i]=1;
                dfs(i,dst+edge[cur][i]);
                mark[i]=0;//需要在深度遍历返回时将访问标志置0
            }
         }
         return;
    }
bellman-ford
for(k=1;k<=n-1;k++)  //外循环循环n-1次,n为顶点个数
    for(i=1;i<=m;i++)//内循环循环m次,m为边的个数,即枚举每一条边
        if(dis[v[i]]>dis[u[i]]+w[i])//尝试对每一条边进行松弛,与Dijkstra算法相同
            dis[v[i]]=dis[u[i]]+w[i]; 

例子:1003 Emergency (25 分)

1.以深度优先为基础

#include <iostream>
using namespace std;

const int MAX=500;
const int INF=10000000;
int countMax=0,maxTeam[500]={0},c2Profile[500]={INF},k=0,targetProfile=INF,targetTeam=0;
void DFS(int N,int profile[][MAX],int c1,int c2,int c[],int visited[],int team,int minProfile) {

    if(c1==c2){
        maxTeam[k]=team;
        if(targetProfile>minProfile)
            targetProfile=minProfile;
        c2Profile[k]=minProfile;
        k++;
//        cout<<"-"<<team<<endl;
        return;
    }

    visited[c1]=1;
    for (int i = 0; i < N; i++) {
        if (profile[c1][i]!= 0&&visited[i]!=1){
            visited[i]=1;
//            cout<<"--"<<team<<"+"<<c[i]<<endl;
//           cout<<i<<"~"<<minProfile<<"~"<<c1<<endl;
            DFS(N, profile, i,c2,c,visited,team + c[i],minProfile + profile[c1][i]);
            visited[i]=0;
        }
    }
}

int main() {
    int N,M,C1,C2,c1,c2,l;

    int c[MAX],visited[MAX]={0};
    int profile[MAX][MAX];

    cin >> N >> M >> C1 >> C2;
    for(int i=0;i<N;i++)
        cin >> c[i];

    for(int i=0;i<N;i++)
        for(int j=0;j<N;j++)
            profile[i][j]=0;

    for(int j=0;j<M;j++){
        cin >> c1 >> c2 >> l;
        profile[c1][c2]=l;
        profile[c2][c1]=l;
    }

    DFS(N, profile, C1,C2,c,visited,0,0);

    for(int i=0;i<k;i++)
        if(c2Profile[i]==targetProfile) {
            countMax++;
            if(targetTeam<maxTeam[i])
                targetTeam=maxTeam[i];
        }
    cout << countMax <<" "<< targetTeam+c[C1] <<endl;
    return 0;
}

2.使用dijkstra

时间复杂度 O(V²)

#include <iostream>

using namespace std;

const int MAX = 500;
const int INF = 10000000;
int N, M, C1, C2, c1, c2, l;
int numPath[500] = {0}, maxTeam[500] = {0};

void Dijkstra(int profile[][MAX], int dist[], int visited[], const int team[]) {
    int min = 0, minPath = INF;
    dist[C1] = 0;
    numPath[C1] = 1;
    maxTeam[C1] = team[C1];
    for (int i = 0; i < N; i++) {
        if (profile[C1][i] != 0) {
            dist[i] = profile[C1][i];
        }
//        cout << dist[i] << endl;
    }
    for (int j = 0; j < N; j++) {
        for (int i = 0; i < N; i++)
            if (visited[i] == 0 && dist[i] < minPath) {
                minPath = dist[i];
//                maxTeam[i] = team[i];
                min = i;
            }
//        cout << "+" << min << " " << minPath << endl;
        if (min == INF) break;
        visited[min] = 1;
        for (int i = 0; i < N; i++) {
            if (profile[min][i] != 0 && dist[i] > dist[min] + profile[min][i]) {
                dist[i] = dist[min] + profile[min][i];
                numPath[i] = numPath[min];
                maxTeam[i] = maxTeam[min] + team[i];
//                cout << "-" << i << " " << dist[min] << " " << numPath[i] << " " << maxTeam[i] << endl;
            } else if (profile[min][i] != 0 && dist[i] == dist[min] + profile[min][i]) {
                numPath[i] = numPath[i] + numPath[min];
                if (maxTeam[i] < maxTeam[min] + team[i])
                    maxTeam[i] = maxTeam[min] + team[i];
//                cout << "~" << i << " " << numPath[i] << " " << maxTeam[i] << endl;
            }
        }
        minPath = INF;
    }
}

int main() {
    int team[MAX] = {0}, dist[MAX], visited[MAX] = {0};
    int profile[MAX][MAX];

    cin >> N >> M >> C1 >> C2;
    for (int i = 0; i < N; i++)
        cin >> team[i];

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++)
            profile[i][j] = 0;
        dist[i] = INF;
//        cout<<dist[i]<<endl;
    }

    for (int j = 0; j < M; j++) {
        cin >> c1 >> c2 >> l;
        profile[c1][c2] = l;
        profile[c2][c1] = l;
    }

    Dijkstra(profile, dist, visited, team);

    cout << numPath[C2] << " " << maxTeam[C2] << endl;
    return 0;
}

3.使用bellman-ford

时间复杂度 O(VE)

4.使用SPFA

连通图-拓扑

无向图

1.连通:检查连通分支(相连的点的一个小团体)个数

并查集

2.求桥

有向图
离散定义

1.强连通

tarjan(u){
  DFN[u]=Low[u]=++Index // 为节点u设定次序编号和Low初值
  Stack.push(u)   // 将节点u压入栈中
  for each (u, v) in E // 枚举每一条边
    if (v is not visted) // 如果节点v未被访问过
        tarjan(v) // 继续向下找
        Low[u] = min(Low[u], Low[v])
    else if (v in S) // 如果节点u还在栈内
        Low[u] = min(Low[u], DFN[v])
  if (DFN[u] == Low[u]) // 如果节点u是强连通分量的根
  repeat v = S.pop  // 将v退栈,为该强连通分量中一个顶点(下三句即打印栈内所有元素)
  print v
  until (u== v)
}

2.弱连通

3.半连通

给定有向图 G = (V, E) ,如果对于所有结点对u,v ∈ V,我们有u→v或v→u,则G是半连通的。请给出一个有效的算法来判断图G是否半连通的。证明算法正确性并分析运行时间。

4.单连通

对于有向图 G = (V, E) 来说,如果 u ~> v 意味着图 G 包含一条从 u 到 v 的简单路径,则图 G 是单连通图。请给出一个有效算法来判断一个有向图是否单连通图。

-to be continued

上一篇 下一篇

猜你喜欢

热点阅读