ltx_zero

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Bellman Ford

进行n-1轮(最多n-1层,就是[0,n-2]),每次将所有的边松弛,如果进行之后还能松弛,说明是负环

这个复杂度是O(VE),dijkstra是O(V^2+E)

  • 使用邻接表而不是邻接矩阵,邻接矩阵复杂度会上升
  • 邻接表在使用边的时候,判断好Adj[u][j]是对应的边,d[Adj[u][j].v]是对应边终点的d,中间距离dis是Adj[u][j].dis,这段容易搞错
  • 使用set要用insert,因为多轮松弛肯定会多次反复访问重复点,因此要用set
  • 在相等的时候,num的修改就是清零重新计算。(这个也导致不能存完pre等结束以后全部重新计算)
  • 初始num[st]=1;
#include<stdio.h>
#include<string.h>
#include<set>
#include<vector>
using namespace std;
int n,m,st,ed;
const int INF=10000;
int d[1000],w[1000],num[1000];//w代表累计,num是路径数
set<int>pre[1000];
int weight[1000]={0};
struct Node{
    int v;
    int dis;
    Node(int tempv,int tempdis)
    {
        v=tempv;
        dis=tempdis;
    }
};
vector<Node>Adj[1000];
void Bellman(int st)
{
    fill(d,d+n,INF);
    memset(num,0,sizeof(num));
    for(int i=0;i<=n-1;i++)
        w[i]=weight[i];
    /*memset(w,0,sizeof(w));
    w[st]=weight[st];*/
    d[st]=0;
    num[st]=1;
    for(int i=0;i<n-1;i++)
    {
        for(int u=0;u<=n-1;u++)
        {
            for(int j=0;j<Adj[u].size();j++)
            {
                int temp=Adj[u][j].v;
                if(d[temp]>d[u]+Adj[u][j].dis)
                {
                    pre[temp].clear();
                    pre[temp].insert(u);
                    w[temp]=w[u]+weight[temp];
                    d[temp]=d[u]+Adj[u][j].dis;
                }
                else if(d[temp]==d[u]+Adj[u][j].dis)
                {
                    pre[temp].insert(u);
                    w[temp]=max(w[temp],(w[u]+weight[temp]));
                    set<int>::iterator it=pre[temp].begin();
                    num[temp]=0;
                    for(it=pre[temp].begin();it!=pre[temp].end();it++)
                    {
                        num[temp]+=num[*it];
                    }
                }
            }
        }
    }
}
int main()
{
    scanf("%d %d %d %d",&n,&m,&st,&ed);
    for(int i=0;i<=n-1;i++)
        scanf("%d",&weight[i]);
    for(int i=1;i<=m;i++)
    {
        int temp1,temp2,temp3;
        scanf("%d %d %d",&temp1,&temp2,&temp3);
        Adj[temp1].push_back(Node(temp2,temp3));
        Adj[temp2].push_back(Node(temp1,temp3));
    }
    Bellman(st);
    printf("%d %d",num[ed],w[ed]);
    return 0;
}
View Code

 A1003的代码。

floyd是用来解决多源最短路,复杂度o3

注意,这个本质上是贪心,在i-j的路径上有一堆点,每次通过一个点松弛,在松弛到最大点的时候,他的左边和右边都取到了最小值,那么他也是,往里推也一样,所以三层循环成立。

每次选好点以后,对整个图松弛,所以选点在最外层。

关于fill函数

fill(a,a+n,INF)

如果是二维数组fill(a[0],a[0]+maxn*maxn,INF)

a[0]才是首地址

fill在iostream头文件里面

以有向图为例的floyd代码

#include<stdio.h>
#include<iostream>
using namespace std;
int n,m,G[100][100]={0};
const int INF=10000;
int main()
{
    scanf("%d %d",&n,&m);
    fill(G[0],G[0]+100*100,INF);
    for(int i=1;i<=m;i++)
    {
        int temp1,temp2,temp3;
        scanf("%d %d %d",&temp1,&temp2,&temp3);
        G[temp1][temp2]=temp3;
        //G[temp2][temp1]=temp3;
    }
    for(int i=0;i<=n-1;i++)
        G[i][i]=0;
    for(int k=0;k<=n-1;k++)
    {
        for(int i=0;i<=n-1;i++)
        {
            for(int j=0;j<=n-1;j++)
                    G[i][j]=min(G[i][j],(G[i][k]+G[k][j]));
        }
    }
    for(int i=0;i<=n-1;i++)
    {
        for(int j=0;j<=n-1;j++)
        {
            printf("%d ",G[i][j]);
        }
        printf("\n");
    }
    return 0;
}
View Code

 

posted on 2020-03-13 00:10  ltx_zero  阅读(137)  评论(0编辑  收藏  举报