1. 程式人生 > 其它 >[概率期望]做題記錄-換教室

[概率期望]做題記錄-換教室

單源最短路徑演算法,其實就是進行鬆馳的演算法。
有Dijkstra/Bellman ford/SPFA 這三種演算法
如圖所示:

演算法模板:
共用程式碼

#define NMAX 105
#define EMAX 10005
int head[NMAX];
int dist[NMAX];
int ver[EMAX];
int nxt[EMAX];
int wi[EMAX];
int tot;

void add(int u,int v,int w){
	ver[++tot] = v;
	nxt[tot] = head[u];
	head[u] = tot;
	wi[tot] = w;
}

bool relax(int u,int v,int w){
	if ( dist[v] > dist[u] + w ){
		dist[v] = dist[u] + w;
		return true;
	}
	return false;
}

void reset(){
	memset(ver,0,sizeof(ver));
	memset(head,0,sizeof(head));
	memset(wi,0,sizeof(wi));
	memset(nxt,0,sizeof(nxt));
	tot = 0;
}

Bellman ford

int bellmanford(int n,int source,int target){
	dist[source] = 0;
	for( int i=1;i<n;i++ ){
		bool flag = false;//tle解決方案
		for(int u=1;u<=n;++u){
			for( int e=head[u];e>0;e=nxt[e] ){
				int v = ver[e];
				int w = wi[e];
				flag = relax(u,v,w) || flag;
			}
		}
		if ( !flag ) break;
	}
	return dist[target];
}

spfa

int spfa(int n,int source,int to){
    memset(bv,0,sizeof(bv));
    dist[source] = 0;
    list<int> li;
    li.push_back(source);
    //bv是用來判斷是否在佇列中的
    //並不是  是否已經被訪問過。這點與dijkstra不同
    bv[source] = true;
    while(!li.empty()){
        int u = li.front();
        li.pop_front();
        bv[u] = false;
        for(int e=head[u];e;e=nxt[e]){
            int v = ver[e];
            if(dist[v]>dist[u] + wi[e]){
                dist[v] =dist[u] + wi[e];
                if ( !bv[v]){
                    li.push_back(v);
                    bv[v] = true;
                }
            }
        }
    }
    return dist[to];
}

Dijkstra

int dijkstra(int n,int source,int to){
	memset(bv,0,sizeof(bv));
	dist[source] = 0;
	priority_queue<pair<int,int>> q;
	q.push(pair<int,int>(0,source));
	while(!q.empty()){
		int u = q.top().second;
		q.pop();
		if ( bv[u]) continue;
		bv[u] = true;
		for( int e=head[u];e>0;e=nxt[e]){
			int v = ver[e];
			if ( dist[v] > dist[u] + wi[e]) {
				dist[v] = dist[u] + wi[e];
				q.push(pair<int,int>(-dist[v],v));
			}
		}
	}
	return dist[to];
}