最短路算法

@

Dijkstra堆优化

dijkstra的原理/流程?
dijkstradijkstra本质上的思想是贪心,它只适用于不含负权边的图.
我们把点分成两类,一类是已经确定最短路径的点,称为"白点",另一类是未确定最短路径的点,称为"蓝点"
dijkstradijkstra的流程如下::
1.1. 初始化dis[start] = 0,dis[start]=0,其余节点的disdis值为无穷大.
2.2. 找一个disdis值最小的蓝点x,x,把节点xx变成白点.
3.3. 遍历xx的所有出边(x,y,z),(x,y,z),若dis[y] > dis[x] + z,dis[y]>dis[x]+z,则令dis[y] = dis[x] + zdis[y]=dis[x]+z
4.4. 重复2,32,3两步,直到所有点都成为白点..
时间复杂度为O(n^2)O(n
2
)
dijkstradijkstra为什么是正确的
当所有边长都是非负数的时候,全局最小值不可能再被其他节点更新.所以在第22步中找出的蓝点xx必然满足:dis[x]:dis[x]已经是起点到xx的最短路径..我们不断选择全局最小值进行标记和拓展,最终可以得到起点到每个节点的最短路径的长度

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define inf 2147483647
int n,m,s,a,b,c;
struct node
{
    int next,to;
    int w;
}edge[5000001];
struct fow{
    int pt,cost;
};
int top=0;
int dis[5000001],vis[5000001],head[5000001];
struct cmp{
    bool operator()(fow a,fow b){
        return a.cost>b.cost;//important 
    }
};
void add(int from,int to,int w) 
{ 
  edge[++top].next=head[from];
  edge[top].to=to;
  edge[top].w=w;
  head[from]=top; 
}
void dijkstra(){
    priority_queue<fow,vector<fow>,cmp> q;
    fow r;
    r.pt=s;
    r.cost=0;
    dis[s]=0;
    q.push(r);
    while(!q.empty()){
        fow nt=q.top();
        q.pop();
        int now=nt.pt;
        //int nc=nt.cost;
        if(vis[now]) continue;
        else vis[now]=1;
        for(int i=head[now];i;i=edge[i].next){
        	int next=edge[i].to;
        	if(dis[next]>dis[now]+edge[i].w){
        		dis[next]=dis[now]+edge[i].w;
        		if(!vis[next]){
        			fow to_push;
        			to_push.pt=next;
        			to_push.cost=dis[next];
        			q.push(to_push);
        		}
        	}
        }
    }
}
int main()
{
    cin>>n>>m>>s;
    for(int i=1;i<=n;i++) dis[i]=inf;
    for(int i=1;i<=m;i++){
        cin>>a>>b>>c;
        add(a,b,c);
    }
    dijkstra();
    for(int i=1;i<=n;i++){
    	cout<<dis[i]<<' ';
    }
    return 0;
}

最短路计数

SPFA的过程中dp
if(dis[next]==dis[now]+edge[i].w) cnt[next]+=cnt[now];

// luogu-judger-enable-o2
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
#define inf 2147483647
#define maxn 2000001
struct node
{
    int u,v;
    int w;
}edge[maxn];
int top=0;
int dis[maxn],vis[maxn],head[maxn],cnt[maxn];
void add(int from,int to,int dis) 
{ 
  edge[++top].u=head[from]; 
  edge[top].v=to; 
  edge[top].w=dis; 
  head[from]=top; 
}
int n,m,a,b,c;
void spfa(int s)
{
    queue <int> q;
    for(int i=1;i<=n;i++)
    {
        vis[i]=0;
        dis[i]=inf;
    }
    q.push(s);
    vis[s]=1;
    dis[s]=0;
    cnt[s]=1;
    while(!q.empty())
    {
    	int now=q.front();
    	q.pop();
    	vis[now]=0;
    	for(int i=head[now];i;i=edge[i].u)
    	{
    		int next=edge[i].v;
    		if(dis[next]>dis[now]+edge[i].w)
    		{
    			dis[next]=dis[now]+edge[i].w;
    			cnt[next]=cnt[now];
    			if(!vis[next])
    			{
    				q.push(next);
    				vis[next]=1;
                }
            }
            else if(dis[next]==dis[now]+edge[i].w){
            	cnt[next]+=cnt[now];
            	cnt[next]%=100003;
            }
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>a>>b;
        add(a,b,1);
        add(b,a,1);
    }
    spfa(1);
    for(int i=1;i<=n;i++){
    	cout<<cnt[i]<<endl;
    }
    return 0;
}

SPFA判负环

一个点最多被访问n-1次吧。。
然后如果访问次数>=n就有负环
复杂度应该不太高

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int read(){
    int x=0;char ch=getchar();bool pos=1;
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return pos?x:-x;
}
int n,m,head[300001],top=0,dis[300001],cnt[300001],vis[300001];
struct node{
    int to,next,w;
}edge[300001];
void add(int from,int to,int w){
    edge[++top].to=to;
    edge[top].w=w;
    edge[top].next=head[from];
    head[from]=top;
}
int spfa(){
    for(int i=1;i<=n;i++){
        dis[i]=999999999;
        vis[i]=0;
        cnt[i]=0;
    }
    vis[1]=1;
    dis[1]=0;
    queue<int>q;
    q.push(1);
    while(!q.empty()){
        int now=q.front();
        vis[now]=0;
        q.pop();
        for(int i=head[now];i;i=edge[i].next){
            int next=edge[i].to;
            if(dis[next]>dis[now]+edge[i].w){
                dis[next]=dis[now]+edge[i].w;
                cnt[now]++;
                if(cnt[now]>=n) return 1;
                if(!vis[next]){
                    vis[next]=1;
                    q.push(next);
                }
            }
        }
    }
    return 0;
}
void solve(){
    n=read();m=read();
    memset(head,0,sizeof(head));
    for(int i=1;i<=m;i++){
        int x=read(),y=read(),w1=read();
        add(x,y,w1);
        if(w1>=0) add(y,x,w1);
    }
    if(spfa()) cout<<"YE5\n";
    else cout<<"N0\n";
    return;
}
int main(){
    int t=read();
    for(int i=1;i<=t;i++){
        top=0;
        solve();
    }
    return 0;
} 
posted @ 2019-07-27 23:09  lcyfrog  阅读(147)  评论(0编辑  收藏  举报