PTA1018 Public Bike Management (30分)

題目:click me~

題意: 

城市公共自行車可在任意站點借還車,每個站點最佳狀態是停一半的自行車。管理員在站點0,只要有problem station需要,管理員就要走最短路徑  去調整problem station 以及最短路上的站點到最佳狀態。

1.若是有幾條相同長度的路徑,則取需要從站點0帶出自行車最少數的那條路。

2.滿足1,若是需要自行車數仍然相同,則取要帶回站點0自行車最少數的那條路。

輸出:需要自行車數  最短路徑 帶回自行車數  

解題思路:

1.用dijsktra算法計算出從點0出發到任意點的最短路,並且記錄路徑。記錄路徑的方法:n個頂點各自開一個vector,用來記錄前驅節點(一個節點可能有多個前驅,因此處理長度相同的多條路徑要用dfs)。

2.求出最短路後,用dfs遍歷剛纔記錄的最短路徑。求出minNeed及minBack。

溫故:

Dijsktra算法(求正權圖中的最短路)    

  • 算法步驟:

1.將點集v分成兩個集合A和B,A中點表示已經求得源點到其的最短路,B中表示待求。(這裏我用visit[]來寫,true表示在A中,false表示還在B中)

2.每次將點加入A中都要維護數組dis[](表示源點到各點的最短路長度)

3.每次從B中挑選一個到達A中的點邊權最小的點。

4.不斷加入A,直到B爲空。

  • 算法代碼:
    	dis[0] = 0;
    	for (int i = 0;i <= n;i++) {
    		int u = -1, minn = inf;
    		for (int j = 0;j <= n;j++) {
    			if (visit[j] == false && dis[j] < minn) {
    				u = j;
    				minn = dis[j];
    			}
    		}
    		if (u == -1)break;//所有點都visit了,退出循環
    		visit[u] = true;
    		for (int v = 0;v <= n;v++) {
    			if (visit[v] == false && e[u][v] != inf) {
    				if (dis[v] > dis[u] + e[u][v]) {
    					dis[v] = dis[u] + e[u][v];
    					pre[v].clear();
    					pre[v].push_back(u);
    				}
    				else if (dis[v] == dis[u] + e[u][v]) {
    					pre[v].push_back(u);
    				}
    			}
    		}
    	}

     

code:

#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<vector>
using namespace std;
const int inf = 99999999;
int cmax, n, sp, m;
int minNeed = inf, minBack = inf;
int e[510][510], dis[510], weight[510];
bool visit[510];
vector<int> pre[510], path, temppath;
void dfs(int v) {
	temppath.push_back(v);
	if (v == 0) {
		int need = 0, back = 0;
		for (int i = temppath.size() - 1;i >= 0;i--) {
			int id = temppath[i];
			if (weight[id] > 0) {
				back += weight[id];
			}
			else {
				if (back > (0 - weight[id])) {
					back += weight[id];
				}
				else {
					need += (0 - weight[id]) - back;
					back = 0;
				}
			}
		}
		if (need < minNeed) {
			minNeed = need;
			minBack = back;
			path = temppath;
		}
		else if (need == minNeed && back < minBack) {
			minBack = back;
			path = temppath;
		}
		temppath.pop_back();//刪除vector中最後一個元素
		return;
	}
	for (int i = 0;i < pre[v].size();i++)
		dfs(pre[v][i]);
	temppath.pop_back();
}
int main() {
	fill(e[0], e[0] + 510 * 510, inf);
	fill(dis, dis + 510, inf);
	scanf("%d%d%d%d", &cmax, &n, &sp, &m);
	for (int i = 1;i <= n;i++) {
		scanf("%d", &weight[i]);
		weight[i] = weight[i] - cmax / 2;
	}
	for (int i = 0;i < m;i++) {
		int a, b;
		scanf("%d%d", &a, &b);
		scanf("%d", &e[a][b]);
		e[b][a] = e[a][b];
	}
	dis[0] = 0;
	for (int i = 0;i <= n;i++) {
		int u = -1, minn = inf;
		for (int j = 0;j <= n;j++) {
			if (visit[j] == false && dis[j] < minn) {
				u = j;
				minn = dis[j];
			}
		}
		if (u == -1)break;//所有點都visit了,退出循環
		visit[u] = true;
		for (int v = 0;v <= n;v++) {
			if (visit[v] == false && e[u][v] != inf) {
				if (dis[v] > dis[u] + e[u][v]) {
					dis[v] = dis[u] + e[u][v];
					pre[v].clear();
					pre[v].push_back(u);
				}
				else if (dis[v] == dis[u] + e[u][v]) {
					pre[v].push_back(u);
				}
			}
		}
	}
	dfs(sp);
	printf("%d 0", minNeed);
	for (int i = path.size() - 2;i >= 0;i--)
		printf("->%d", path[i]);
	printf(" %d", minBack);
	
	return 0;
}

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章