求最短路——迪杰斯特拉算法的优化

original link - http://acm.zjnu.edu.cn/CLanguage/showproblem?problem_id=1211

题意:

给定M条边,N个点的带权无向图,求1到N的最短路

解析:

先讲一下一般做题时可以用到的优化:

1. 显然,当一个点被 v i s vis vis过(当作最近点后),下一次不会再 p u s h push push这个点了,但是不保证之前是否有压入这个点的不良状态。所以被 v i s vis vis过的点直接 c o n t i n u e continue continue可以保证每个点只跑一次。
2. 假设我们只求到一个点的最短路,那么显然,如果当前更新的答案劣于终点的答案,就不用压到队列里面去了。
3. 如果终点作为最近的点时,直接输出答案即可。

迪杰斯特拉模板:

#include
#include
#include
#include
#define N 100009
using namespace std;
int read(){ int ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
} 
int head[N],now;
struct edge{
	int to,nex,val;
}e[10*N];
void add(int a,int b,int v){
	e[++now].to=b;e[now].nex=head[a];e[now].val=v;head[a]=now; 
	e[++now].to=a;e[now].nex=head[b];e[now].val=v;head[b]=now;
}

int n,m,a,b,v;

struct node{
	int _id,dis;
	node(int _id,int dis):_id(_id),dis(dis){}
	bool operator < (const node &a) const{
		return dis>a.dis;
	}
};
priority_queue<node>Q;
int vis[N];
int dist[N];

int main(){
	memset(head,-1,sizeof(head));now=0;
	memset(dist,0x3f,sizeof(dist));
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		a=read();b=read();v=read();add(a,b,v);
	}
	Q.push(node(1,0));
	dist[1]=0;
	while(!Q.empty()){
		int j=Q.top()._id;Q.pop();
		if(vis[j])continue;
		vis[j]=1;
		if(j==n){
            printf("%d\n",dist[n]);
            break;
		}
		for(int i=head[j];i!=-1;i=e[i].nex){
			if(vis[e[i].to])continue;
			if(dist[e[i].to]-e[i].val>dist[j] && dist[n]-e[i].val>dist[j]){
				dist[e[i].to]=e[i].val+dist[j];
				Q.push(node(e[i].to,dist[e[i].to]));
			}
		}
	}
} 

还有一种优化,用 p a i r pair pair代替 s t r u c t struct struct,因为 p a i r pair pair是自带的东西,比较大小什么的都比自己写的结构体优一点。

因为优先队列按照 f i r s t first first升序排序,所以压进优先队列里面的 p a i r pair pair f i r s t first first为距离, s e c o n d second second为点的id

#include
#include
#include
#include
#include
#include
#define N 100009
#define ll long long
#define pill pair
#define pb push_back
#define mk make_pair
using namespace std;

ll read(){ ll ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;}


vector<pill> v[N];


priority_queue<pill,vector<pill>,greater<pill> >Q;
int vis[N];
int dist[N];

int main(){
	memset(dist,125,sizeof(dist));
	int n=read(),m=read();
	for(int i=1;i<=m;i++){
		int a=read(),b=read(),c=read();
		v[a].pb(mk(b,c));v[b].pb(mk(a,c));
	}
	Q.push(mk(0,1));dist[1]=0;
	while(!Q.empty()){
		int j=Q.top().second;Q.pop();
		if(vis[j])continue;vis[j]=1;
		for(int i=0;i<v[j].size();i++){
			if(vis[v[j][i].first])continue;
			if(dist[v[j][i].first]>dist[j]+v[j][i].second){
				dist[v[j][i].first]=dist[j]+v[j][i].second;
				Q.push(mk(dist[v[j][i].first],v[j][i].first));
			}
		}
	}
	printf("%d\n",dist[n]);
} 

例题

original link - http://acm.zjnu.edu.cn/CLanguage/showproblem?problem_id=1412)

#include
#include
#include
#include
#include
#include
#include
#define D long long
#define pill pair
#define mk make_pair
using namespace std;

vector<pill>V[10009];
priority_queue<pill,vector<pill>,greater<pill> >Q;
int vis[10009],dis[10009];
int n,m;
int main(){
	while(cin>>m>>n){
		while(!Q.empty())Q.pop();
		for(int i=1;i<=n;i++)dis[i]=1e9,vis[i]=0,V[i].clear();
		while(m--){
			int a,b,v;scanf("%d%d%d",&a,&b,&v);
			V[a].push_back(mk(b,v));
			V[b].push_back(mk(a,v));
		}
		dis[1]=0;vis[1]=1;
		Q.push(mk(0,1));
		while(!Q.empty()){
			pill e=Q.top();Q.pop();
			int Id=e.second,val=e.first;
			vis[Id]=1;
			if(Id==n)break;
			for(int i=0;i<V[Id].size();i++){
				int a=V[Id][i].first,b=V[Id][i].second;
				if(vis[a])continue;
				if(dis[Id]<dis[a]-b){
					dis[a]=dis[Id]+b;
					Q.push(mk(dis[a],a));
				}
			}
		}
		printf("%d\n",dis[n]);
	}
}

你可能感兴趣的:(图论/搜索)