基本思想:
首先的考虑是采用大数下的迪杰斯特拉来计算,比较繁琐,而且有多重边的情况;
其次可以采用稀疏图下的最小生成树算法来做;
原因:
1.给出的边集天然递增;
2.边满足后续边总大于之前边的和,所以天然可以保证贪心构造生成树,即为最短路径;
值得注意的是老生常谈的取模问题:
方法一:
#include<iostream> #include<vector> #include<string> using namespace std; const int maxn = 110; string SINF = "1"; int m, n; string ma[maxn][maxn]; string dis[maxn]; bool vis[maxn]; void mutiple(string &s, int n) { int carry = 0; for (int i = s.size() - 1; i >= 0; i--) { int temp = (s[i] - '0')*n + carry; s[i] = temp % 10+'0'; carry = temp / 10; } while (carry != 0) { s = char(carry % 10 + '0') + s; carry /= 10; } } bool cmp(string a, string b) { //如果a>b返回true; if (a.size() > b.size()) return true; else if (a.size() == b.size()) return a > b; else return false; } string cntmut(int k) { string s = "1"; for (int i = 0; i < k; i++) { mutiple(s, 2); } return s; } string bigadd(string a, string b) { int len = a.size() - b.size(); if (len > 0) { while (len != 0) { b = '0' + b; len--; } } else if(len<0){ while (len != 0) { a = '0' + a; len++; } } int carry = 0; for (int i = a.size() - 1; i >= 0; i--) { int temp = carry + (a[i] - '0') + (b[i] - '0'); a[i] = temp % 10+'0'; carry = temp / 10; } if (carry != 0) { a = '1' + a; } while (a.size() > 1 && a[0] == '0') a.erase(0); return a; } void dij(int st) { dis[st] = "0"; for (int u = 0; u < n; u++) { int index = -1; string Min = SINF; for (int i = 0; i < n; i++) { if (!vis[i] &&cmp(Min, dis[i])) { Min = dis[i]; index = i; } } if (index == -1) return; vis[index] = true; for (int i = 0; i < n; i++) { string ss = bigadd(dis[index], ma[index][i]); if (!vis[i] && ma[index][i] != SINF && cmp(dis[i], ss)) dis[i] = ss; } //cout << 1 << endl; } } void init() { fill(vis, vis + maxn, false); fill(ma[0], ma[0] + maxn * maxn, SINF); fill(dis, dis + maxn, SINF); } void output() { for (int i = 1; i < n; i++) { if (dis[i].size() > 5) { string s = dis[i].substr(dis[i].size() - 5, 5); while (s.size() > 1 && s[0] == '0') s.erase(0,1); cout << s <<endl; } else { cout << dis[i] << endl; } } } int main() { while (cin >> n >> m) { SINF = cntmut(m + 2); init(); int a, b; for (int i = 0; i < m; i++) { cin >> a >> b; if(ma[a][b]==SINF) ma[a][b] = ma[b][a] = cntmut(i); } dij(0); output(); } }
方法二:
#include<iostream> #include<vector> #include<string> #include<stdlib.h> #include<queue> using namespace std; const int INF = 1000000; const int maxn = 110; int n, m; int father[maxn]; int dist[maxn][maxn]; int dis[maxn]; bool vis[maxn]; int findfather(int n) { while (n != father[n]) n = father[n]; return n; } void Union(int x, int y) { int xx = findfather(x); int yy = findfather(y); father[xx] = yy; } void init() { for (int i = 0; i < n; i++) { father[i] = i; } fill(dist[0], dist[0] + maxn * maxn, INF); fill(dis, dis + maxn, INF); fill(vis, vis + maxn, false); } int cntmod(int k) { int num = 1; for (int i = 0; i < k; i++) { num = num % 100000; num *= 2; num = num % 100000; } return num; } void dfs(int st,int d) { dis[st] = d; vis[st] = true; for (int i = 0; i < n; i++) { if (dist[st][i] != INF&&!vis[i]) { int dd = d % 100000 + dist[st][i] % 100000; dfs(i, dd%100000); } } vis[st] = false; } int main() { while (cin >> n >> m) { int a, b; init(); for (int i = 0; i < m; i++) { cin >> a >> b; int faa = findfather(a); int fab = findfather(b); if (faa != fab) { Union(a, b); dist[a][b] = dist[b][a] = cntmod(i); } } dfs(0, 0); for (int i = 1; i < n; i++) { cout << dis[i] << endl; } } return 0; }