牛客oj 習題11.6最短路徑(並查集+Dijkstra+大數加乘比較)

 

 

題目鏈接:click here

題意:中問題,數據非常大

思路:

(1)、由於後輸入的邊一定要大於之前所有邊的總和,所以用並查集解決多餘邊問題,若輸入邊的兩點不在同一集合,則合併,代表這個集合內的邊都是儘可能小的邊,若輸入邊的兩點已經在同一集合,則將邊捨棄;

(2)、使用Dijkstra算法解決最短路問題,由於輸入數據太龐大,所以用字符串存儲以及運算,這裏用到了大數加法、乘法、比較;

(3)、將求得的字符串轉化爲整形數字並輸出後5位。

PS:這題昨天寫了我一天,練到了好多知識點(並查集屬於優化範疇)。越長的代碼越是能鍛鍊自己的代碼能力,也值了。只是這題因爲不會改bug也看了些題解,其中有些人只用並查集+最短路沒用大數就過去了,他們大多在輸入邊的時候就對100000取了模,我認爲這樣想是錯誤的。題目中說數值太大的以MOD 100000 的結果輸出,沒說輸入的邊太大就模100000,而且不管floyd還是dijkstra都要比較距離值,取模後很顯然無法正確比較。然而他們還是過了,我認爲是數據還是弱,弱到邊的大小在小於100000的時候就全將節點合併,以至於後面大於100000的邊都捨去,導致結果依然不變,但這並不能說明這題解答正確。

再PS:大數比較函數一開始寫居然寫成了從低位比到高位,一度改代碼改到絕望半天才找出問題,總體來說這題體驗不錯。

 

 

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <sstream>
#include <queue>
#include <climits>
 
using namespace std;
 
const int MAXN = 105;
const int INF = INT_MAX;

bool BigSmallerCmp(string str1, string str2){
	if(str1.size() < str2.size()) return true;
	else if(str1.size() > str2.size()) return false;
	else{
		for(int i = 0; i < str1.size(); i++){//從高位向低位比較 
			if((str1[i] - '0') > (str2[i] - '0')) return false;
			else if((str1[i] - '0') < (str2[i] - '0')) return true;
		}
	}
	return false;
}

struct Point{
	int number;
	string distance;
	Point(int n, string d): number(n), distance(d) {}
	bool operator< (const Point& c) const{
		return BigSmallerCmp(c.distance, distance);
	}
};

struct Edge{
	int to;
	string length;
	Edge(int t, string l): to(t), length(l) {}
};

int N, M;
int dis[MAXN], father[MAXN], height[MAXN];
string disstr[MAXN], strINF;
bool visit[MAXN];
vector<Edge> graph[MAXN];

string BigMultiple(string str){
	bool carry = false;
	int current;
	string ans;
	for(int i = str.size() - 1; i >= 0; i--){
		current = str[i] - '0';
		current *= 2;
		if(carry) current++;
		carry = false;
		if(current >= 10){
			current -= 10;
			carry = true;
		}
		ans.insert(ans.begin(), 1, current + '0');
	}
	if(carry) ans.insert(ans.begin(), 1, '1');
	return ans;
}

void Change(string& str1, string& str2){
	if(str1.size() < str2.size()){
		string tmp = str1;
		str1 = str2;
		str2 = tmp;
	}
	return;
}

string BigPlus(string str1, string str2){
	Change(str1, str2);
	bool carry = false;
	string ans;
	int current, pos = str1.size() - 1;
	for(int i = str2.size() - 1; i >= 0; i--){
		current = (str2[i] - '0') + (str1[pos--] - '0');
		if(carry) current++;
		carry = false;
		if(current >= 10){
			current -= 10;
			carry = true;
		}
		ans.insert(ans.begin(), 1, current + '0');
	}
	for(int i = pos; i >= 0; i--){
		current = str1[i] - '0';
		if(carry) current++;
		carry = false;
		if(current >= 10){
			current -= 10;
			carry = true;
		}
		ans.insert(ans.begin(), 1, current + '0');
	}
	if(carry) ans.insert(ans.begin(), 1, '1');
	return ans;
}

int Find(int x){
	if(x != father[x]) father[x] = Find(father[x]);
	return father[x];
}

void Union(int x, int y){
	if(height[x] < height[y]) father[x] = y;
	else if(height[y] < height[x]) father[y] = x;
	else{
		father[y] = x;
		height[x]++;
	}
}

void Dijkstra(int start){
	disstr[start] = "0";
	priority_queue<Point> myqueue;
	myqueue.push(Point(start, disstr[start]));
	while(!myqueue.empty()){
		int from = myqueue.top().number;
		myqueue.pop();
		if(visit[from]) continue;
		visit[from] = true;
		for(int i = 0; i < graph[from].size(); i++){
			int to = graph[from][i].to;
			string newedge = BigPlus(disstr[from],  graph[from][i].length);
			if(BigSmallerCmp(newedge, disstr[to])){
				disstr[to] = newedge;
				myqueue.push(Point(to, disstr[to]));
			}
		}
	}
}

void CutAndChange(){
	for(int i = 0; i < N; i++){
		stringstream tmp;
		if(disstr[i] == strINF){
			dis[i] = INF;
			continue;
		}
		if(disstr[i].size() > 5) disstr[i] = disstr[i].substr(disstr[i].size() - 5, 5);
		tmp << disstr[i];
		tmp >> dis[i];
	}
}

void Initial(){
	for(int i = 0; i < N; i++){
		graph[i].clear();
		disstr[i] = strINF;
		father[i] = i;
		height[i] = 0;
		visit[i] = false;
	}
}

int main(){
//	freopen("in.txt", "r", stdin);
	strINF = "1";
	for(int i = 0; i < 502; i++){
		strINF = BigMultiple(strINF);
	}
	while(~scanf("%d %d", &N, &M)){
		Initial();
		string road = "1";
		int A, B, x, y;
		for(int i = 0; i < M; i++){
			scanf("%d %d", &A, &B);
			x = Find(A);
			y = Find(B);
			if(x != y){
				Union(x, y);
				graph[A].push_back(Edge(B, road));
				graph[B].push_back(Edge(A, road));
			}
			road = BigMultiple(road);
		}
		Dijkstra(0);
		CutAndChange();
		for(int i = 1; i < N; i++){
			if(dis[i] == INF) printf("-1\n");
			else printf("%d\n", dis[i]);
		}
	}
	return 0;
}

 

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