题意:
给定数字n,m,(1≤n,m≤500000)
将n变为n*2的花费为2,将n变为n-3的花费为3,要求过程当中所有数字都在[1,500000]区间内。
求将n变为m的最少花费。
思路:
将每个数字视为图论中的点,数字之间的转换视为图论中的边。有向图!
500000个点,连边(i,i*2)权值为2,连边(i,i-3)权值为3
求n至m的最短路就是最小花费
除Floyd之外的方法,时间复杂度均符合要求
1 #include<cstdio> 2 #include<vector> 3 #include<queue> 4 using namespace std; 5 6 const int inf = 99999999; 7 const int maxn = 500000 + 5; 8 struct edge { 9 int v, w; 10 }; 11 vector<vector<edge>>a; 12 vector<int>dis(maxn, inf); 13 vector<bool>flag(maxn, false); 14 15 void add_edge(int u,int v,int w) { 16 edge tmp; 17 tmp.v = v; 18 tmp.w = w; 19 a[u].push_back(tmp); 20 } 21 22 bool legal(int x) { return x > 0 && x <= 500000; } 23 24 void spfa(int s) { 25 queue<int>q; 26 q.push(s); 27 dis[s] = 0;flag[s] = true; 28 while (!q.empty()) { 29 int u = q.front(); q.pop(); flag[u] = false; 30 for (int i = 0; i < a[u].size(); i++) {//扫描所有邻接点 31 if (dis[a[u][i].v] > dis[u] + a[u][i].w) { 32 dis[a[u][i].v] = dis[u] + a[u][i].w; 33 if (!flag[a[u][i].v]) { 34 q.push(a[u][i].v); 35 flag[a[u][i].v] = true; 36 } 37 } 38 } 39 } 40 } 41 42 int main() { 43 int s, t; 44 scanf("%d%d", &s, &t); 45 a.resize(maxn); 46 for (int i = 1; i <= maxn; i++) { 47 if (legal(i * 2)) add_edge(i, i * 2, 2); 48 if (legal(i - 3)) add_edge(i, i - 3, 3); 49 } 50 spfa(s); 51 if (dis[t] != inf)printf("%d ", dis[t]); 52 else printf("-1 "); 53 return 0; 54 }
POJ3268
题意:N 个点,M 条有向边,求问从所有点到 X 的最短路加上从 X 到所有点的最短路加上总和的最大值
解法:这里要明白一件事情,就是点 a 到点 b 的最短路等于所有边反转后点 b 到点 a 的最短路。依据这个原理先算一遍从 X 到所有点的最短路,之后翻转所有边再算一遍即可。
网上说优化的Dijkstra会跑的比SPFA快,hhhh他们还是太年轻了。
1 struct Edge { 2 int from, to, w, next; 3 }; 4 int head[MAXN], vis[MAXN]; 5 int dist[MAXN]; 6 int rev_head[MAXN]; 7 int rev_dist[MAXN]; 8 Edge e[100005], rev_e[100005]; 9 int N, M, tot, X, rev_tot; 10 11 void add_edge(int i, int j, int w) { 12 e[tot].from = i, e[tot].to = j, e[tot].w = w; 13 e[tot].next = head[i]; 14 head[i] = tot++; 15 } 16 17 void add_rev_edge(int i, int j, int w) { 18 rev_e[rev_tot].from = i, rev_e[rev_tot].to = j, rev_e[rev_tot].w = w; 19 rev_e[rev_tot].next = rev_head[i]; 20 rev_head[i] = rev_tot++; 21 } 22 23 void SPFA(int s) { 24 queue<int> q; 25 for (int i = 1; i <= N; i++) dist[i] = INF; 26 memset(vis, false, sizeof(vis)); 27 q.push(s); 28 dist[s] = 0; 29 while (!q.empty()) { 30 int u = q.front(); 31 q.pop(); 32 vis[u] = false; 33 for (int i = head[u]; i != -1; i = e[i].next) { 34 int v = e[i].to; 35 if (dist[v] > dist[u] + e[i].w) { 36 dist[v] = dist[u] + e[i].w; 37 if (!vis[v]) { 38 vis[v] = true; 39 q.push(v); 40 } 41 } 42 } 43 } 44 } 45 46 void rev_SPFA(int s) { 47 queue<int> q; 48 for (int i = 1; i <= N; i++) rev_dist[i] = INF; 49 memset(vis, 0, sizeof(vis)); 50 q.push(s); 51 rev_dist[s] = 0; 52 while (!q.empty()) { 53 int u = q.front(); 54 q.pop(); 55 vis[u] = false; 56 for (int i = rev_head[u]; i != -1; i = rev_e[i].next) { 57 int v = rev_e[i].to; 58 if (rev_dist[v] > rev_dist[u] + rev_e[i].w) { 59 rev_dist[v] = rev_dist[u] + rev_e[i].w; 60 if (!vis[v]) { 61 vis[v] = true; 62 q.push(v); 63 } 64 } 65 } 66 } 67 } 68 69 int main() { 70 #ifndef ONLINE_JUDGE 71 freopen("input.txt", "r", stdin); 72 #endif 73 scanf("%d%d%d", &N, &M, &X); 74 tot = 0, rev_tot = 0; 75 memset(head, -1, sizeof(head)); 76 memset(rev_head, -1, sizeof(rev_head)); 77 int u, v, w; 78 for (int i = 1; i <= M; i++) { 79 scanf("%d%d%d", &u, &v, &w); 80 add_edge(u, v, w); 81 add_rev_edge(v, u, w); 82 } 83 SPFA(X); 84 rev_SPFA(X); 85 int ans = -1; 86 for (int i = 1; i <= N; i++) ans = max(ans, dist[i] + rev_dist[i]); 87 printf("%d ", ans); 88 return 0; 89 }