挑战程序设计(算法和数据结构)—高等图算法

文章目录

          • 多源最短路径
          • 拓扑排序

多源最短路径

题目15.1链接All Pairs Shortest Path
注意点:

  • 边权值可以为负
  • 需要判断负环
  • 输出每两个点之间的距离,如果不连通则输出INF

方法采用弗洛伊德算法,判断负环的方法是算法执行完后如果一个顶点到自身的距离为负,则代表图中有负环。
算法思路是采用了动态规划思想,Ak[i,j]代表经过了k个中间点的从点i到点j的路径长度,可知有
Ak[i,j] = min(Ak-1[i,j], Ak-1[i, k] + Ak-1[k, j]),
即对于对于是否经过第k个中间点,取其路径最短的情况。
且,有Ak[i, k] = min(Ak-1[i, k], Ak-1[i, k] + Ak-1[k, k]) = Ak-1[i, k],可知可以把动态规划的式子转化为:
A[i,j] = min(A[i,j], A[i, k] + A[k, j])。

#include 
using namespace std;

const int MAX = 200;
const long long INF = (1LL<<32);
int V, E, s, t, d;
long long G[MAX][MAX];

void floyd()
{
    for(int k=0; k<V; k++)
    {
        for(int i=0; i<V; i++)
        {
            if(G[i][k]==INF) continue;//防止得到的G的值大于INF,这种情况G[i][j]值不变
            for(int j=0; j<V; j++)
            {
                if(G[k][j]==INF) continue;//防止得到的G的值大于INF,这种情况G[i][j]值不变
                G[i][j] = min(G[i][j], G[i][k]+G[k][j]);
            }
        }
    }
}
bool negative()//判断是否有负环
{
    for(int i=0; i<V; i++)
    {
        if(G[i][i]<0)
            return 1;
    }
    return 0;
}
int main()
{
    cin >> V >> E;
    for(int i=0; i<V; i++)//初始化
    {
        for(int j=0; j<V; j++)
        {
            if(i==j) G[i][j] = 0;
            else G[i][j] = INF;
        }
    }
    for(int i=0; i<E; i++)
    {
        cin >> s >> t >> d;
        G[s][t] = d;
    }
    floyd();
    if(negative())
        cout << "NEGATIVE CYCLE" << endl;
    else
    {
        for(int i=0; i<V; i++)
        {
            for(int j=0; j<V; j++)
            {
                if(j) cout << " ";
                if(G[i][j]!=INF)
                    cout << G[i][j];
                else
                    cout << "INF";
            }
            cout << endl;
        }
    }
    return 0;
}
拓扑排序

题目15.2链接Topological Sort

方法一:
思路是用队列S存入度为0的结点,每从队列中删除一个结点,就更新剩余未入队列的结点的入度,如果结点入度为0,则入队列,直到队列为空,排序完成。

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

const int MAX = 10005;
int V, E, s, t;
int indeg[MAX];
vector<int> G[MAX];//用于邻接表存储图
queue<int> S;//用于记录入度为0且未删除的结点

void load(int u)//用于每删除一个结点,更新其余结点的入度值
{
    for(int i=0; i<G[u].size(); i++)
    {
        if(!indeg[G[u][i]]) continue;
        indeg[G[u][i]]--;
        if(!indeg[G[u][i]])
        {
            S.push(G[u][i]);
        }
    }
}

void topologicalSort()//用队列实现拓扑排列
{
    int u;
    while(!S.empty())
    {
        u = S.front(); S.pop();
        printf("%d\n", u);
        load(u);//将u的邻接点的入度减一,若为0则入队列
    }
}

int main()
{
    memset(indeg, 0, sizeof(indeg));
    scanf("%d %d", &V, &E);
    for(int i=0; i<E; i++)
    {
        scanf("%d %d", &s, &t);
        indeg[t]++;
        G[s].push_back(t);
    }
    for(int i=0; i<V; i++)//初始入队列
    {
        if(!indeg[i])
            S.push(i);
    }
    topologicalSort();
    return 0;
}

方法二:利用BFS使得每一次从一个入度为0的顶点出发,BFS遍历一遍,将遍历过的所有符号条件入度为0的存起来,当从所有结点均BFS一遍后一定保证将所有的边均遍历到,将所有的结果都考虑到。
复杂度为O(|V|+|E|)。

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

const int MAX = 10005;
const int INF = (1<<29);

int V, E, s, t, color[MAX];
int indeg[MAX];
vector<int> G[MAX];//用于邻接表存储图
queue<int> S;//用于记录入度为0且未删除的结点

void bfs(int s)//用于每删除一个结点,更新其余结点的入度值
{
     queue<int> q;
     q.push(s);
     color[s] = 1;
     while(!q.empty())
     {
         int u = q.front(); q.pop();
         S.push(u);
         for(int i=0; i<G[u].size(); i++)
         {
             int v = G[u][i];
             indeg[v]--;
             if(indeg[v]==0 && !color[v])//入度为0且未访问过
             {
                 color[v] = 1;
                 q.push(v);
             }
         }
     }
}

void topologicalSort()//用队列实现拓扑排列
{
    for(int u=0; u<V; u++)
    {
        if(indeg[u]==0 && !color[u])//入度为0且未访问过
            bfs(u);
    }

    while(!S.empty())
    {
        printf("%d\n", S.front());
        S.pop();
    }
}

int main()
{
    memset(indeg, 0, sizeof(indeg));
    memset(color, 0, sizeof(color));
    scanf("%d %d", &V, &E);
    for(int i=0; i<E; i++)
    {
        scanf("%d %d", &s, &t);
        indeg[t]++;
        G[s].push_back(t);
    }

    topologicalSort();
    return 0;
}

你可能感兴趣的:(挑战程序设计-算法和数据结构)