kuangbin专题四:最短路练习
POJ2387 Til the Cows Come Home
思路:dijkstra搜索。
#include<iostream> #include<cstring> #include<queue> using namespace std; const int maxn = 1005; const int maxt = 2005; int T, N; int head[maxn], idx; bool vis[maxn]; int dis[maxn]; struct Node{ int u, dis; bool operator<(const Node& node) const{ return dis > node.dis; } }; struct Edge{ int v, w, next; } edge[2 * maxt]; void addEdge(int u, int v, int w){ idx++; edge[idx].v = v, edge[idx].w = w; edge[idx].next = head[u]; head[u] = idx; } void dijkstra(){ priority_queue<Node> q; memset(dis, 0x3f, sizeof(dis)); dis[N] = 0; Node firstNode = {N, 0}; q.push(firstNode); while(q.size()){ Node node = q.top(); q.pop(); int u = node.u; if(vis[u]) continue; vis[u] = true; for(int i = head[u]; i; i = edge[i].next){ int v = edge[i].v, w = edge[i].w; if(!vis[v] && dis[v] > dis[u] + w){ dis[v] = dis[u] + w; Node nextNode = {v, dis[v]}; q.push(nextNode); } } } } int main(){ cin >> T >> N; for(int i = 1; i <= T; i++){ int u, v, w; cin >> u >> v >> w; addEdge(u, v, w); addEdge(v, u, w); } dijkstra(); cout << dis[1] << endl; return 0; }
思路:dijkstra搜索。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> using namespace std; const int maxn = 205; int N; int head[maxn], idx; bool vis[maxn]; double dis[maxn]; struct Pos{ int x, y; }pos[maxn]; struct Node{ int u; double dis; bool operator<(const Node& node) const{ return dis > node.dis + 1e-6; } }; struct Edge{ int v, next; double w; } edge[2 * maxn * maxn]; void addEdge(int u, int v, double w){ idx++; edge[idx].v = v, edge[idx].w = w; edge[idx].next = head[u]; head[u] = idx; } double Distance(Pos& a, Pos& b){ return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); } void dijkstra(){ priority_queue<Node> q; for(int i = 0; i <= N; i++) dis[i] = 0x3f3f3f3f; dis[1] = 0; Node firstNode = {1, 0}; q.push(firstNode); while(q.size()){ Node node = q.top(); q.pop(); int u = node.u; if(vis[u]) continue; vis[u] = true; for(int i = head[u]; i; i = edge[i].next){ int v = edge[i].v; double w = edge[i].w; if(!vis[v] && dis[v] > max(w, dis[u]) + 1e-6){ dis[v] = max(w, dis[u]); Node nextNode = {v, dis[v]}; q.push(nextNode); } } } } void init(){ memset(vis, 0, sizeof(vis)); memset(head, 0, sizeof(head)); idx = 0; } int main(){ int testId = 0; while(cin >> N && N){ testId++; init(); for(int i = 1; i <= N; i++) cin >> pos[i].x >> pos[i].y; for(int i = 1; i < N; i++) for(int j = i + 1; j <= N; j++){ double d = Distance(pos[i], pos[j]); addEdge(i, j, d); addEdge(j, i, d); } dijkstra(); printf("Scenario #%d\n", testId); printf("Frog Distance = %.3f\n", dis[2]); printf("\n"); } return 0; }
思路:用dijkstra好像会超时,用最小生成树和spfa都可。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> using namespace std; const int maxn = 1005; const int maxm = 1000005; int n, m, idx; int head[maxn], dis[maxn]; bool in_queue[maxn]; struct Edge{ int v, next; int w; } edge[2 * maxm]; void addEdge(int u, int v, int w){ idx++; edge[idx].v = v, edge[idx].w = w; edge[idx].next = head[u]; head[u] = idx; } void spfa(){ memset(in_queue, 0, sizeof(in_queue)); memset(dis, 0, sizeof(dis)); queue<int> q; q.push(1); in_queue[1] = true, dis[1] = 0x3f3f3f3f; while(q.size()){ int u = q.front(); q.pop(); in_queue[u] = false; for(int i = head[u]; i; i = edge[i].next){ int v = edge[i].v, w = edge[i].w; if(dis[v] < min(dis[u], w)){ dis[v] = min(dis[u], w); if(!in_queue[v]){ in_queue[v] = true; q.push(v); } } } } } void init(){ memset(head, 0, sizeof(head)); memset(edge, 0, sizeof(edge)); idx = 0; } int main(){ int T; scanf("%d", &T); for(int t = 1; t <= T; t++){ init(); scanf("%d%d", &n, &m); for(int i = 1; i <= m; i++){ int u, v, w; scanf("%d%d%d", &u, &v, &w); addEdge(u, v, w); addEdge(v, u, w); } spfa(); printf("Scenario #%d:\n", t); printf("%d\n\n", dis[n]); } return 0; }
思路:反向建图,两次dijkstra。
#include<iostream> #include<cstring> #include<queue> using namespace std; const int maxn = 1005; const int maxm = 1e5 + 5; int dis[maxn], rdis[maxn], head[maxn], rhead[maxn]; bool vis[maxn]; int idx; struct Node{ int u, dis; bool operator<(const Node& node) const{ return dis > node.dis; } }; struct Edge{ int v, w, next; } edge[maxm], redge[maxm]; void dijkstra(Edge* e, int* d, int* h, int x){ memset(vis, 0, sizeof(vis)); priority_queue<Node> q; Node node = {x, 0}; q.push(node); d[x] = 0; while(q.size()){ Node unode = q.top(); q.pop(); int u = unode.u; vis[u] = true; for(int i = h[u]; i; i = e[i].next){ int v = e[i].v, w = e[i].w; if(!vis[v] && d[v] > d[u] + w){ d[v] = d[u] + w; Node node = {v, d[v]}; q.push(node); } } } } int main(){ int n, m, x; cin >> n >> m >> x; memset(dis, 0x3f, sizeof(dis)); memset(rdis, 0x3f, sizeof(rdis)); for(int i = 1; i <= m; i++){ int u, v, w; cin >> u >> v >> w; idx++; edge[idx] = {v, w, head[u]}; head[u] = idx; redge[idx] = {u, w, rhead[v]}; rhead[v] = idx; } dijkstra(edge, dis, head, x); dijkstra(redge, rdis, rhead, x); int ans = 0; for(int i = 1; i <= n; i++){ ans = max(ans, dis[i] + rdis[i]); } cout << ans << endl; return 0; }
思路:BellmanFord。
思路:BellmanFord、Flody算法都可。
思路:水题。
#include<iostream> #include<cstring> #include<queue> using namespace std; const int maxn = 110; int n; int head[maxn], idx; int dis[maxn]; bool vis[maxn]; struct Node{ int u; bool operator<(const Node &a) const { return dis[u] > dis[a.u]; } }; struct Edge{ int v, w, next; }edge[maxn * maxn]; void addedge(int u, int v, int w){ idx++; edge[idx] = {v, w, head[u]}; head[u] = idx; } int dijkstra(){ memset(dis, 0x3f, sizeof(dis)); priority_queue<Node> q; dis[1] = 0; Node n1 = {1}; q.push(n1); while (q.size()) { Node p = q.top(); q.pop(); if (vis[p.u]) continue; vis[p.u] = true; for (int i = head[p.u]; i; i = edge[i].next) { Edge &e = edge[i]; if (!vis[e.v] && dis[e.v] > dis[p.u] + e.w) { dis[e.v] = dis[p.u] + e.w; Node ni = {e.v}; q.push(ni); } } } int result = 0; for (int i = 1; i <= n; i++) result = max(result, dis[i]); return result; } int ch2i(char *wc){ if (wc[0] == 'x') return 0x3f3f3f3f; int result = 0; for(int i = 0; wc[i]; i++) { result *= 10; result += wc[i] - '0'; } return result; } void readMatrix() { char wc[10]; for (int i = 2; i <= n; i++) for (int j = 1; j < i; j++) { cin >> wc; int wi = ch2i(wc); addedge(i, j, wi); addedge(j, i, wi); } } int main() { cin >> n; readMatrix(); cout << dijkstra(); }
思路:简单flody算法。
#include<iostream> using namespace std; const int maxn = 110; int n, m, u, v; int dis[maxn][maxn]; void flody(){ for(int k = 1; k <= n; k++) for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if(dis[i][k] && dis[k][j]) dis[i][j] = 1; } int main() { cin >> n >> m; for(int i = 1; i <= m; i++){ cin >> u >> v; dis[u][v] = 1; } flody(); int res = 0; for(int i = 1; i <= n; i++){ int degree = 0; for(int j = 1; j <= n; j++) degree += dis[i][j] + dis[j][i]; if(degree == n-1) res++; } cout << res << endl; return 0; }
思路:Bellman-ford判断是否有环。
#include<iostream> #include<cstring> #include<map> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 35; int n, m, T, idx; float dis[maxn]; struct Edge{ int u, v; float rate; }e[maxn * maxn]; void addedge(int u, int v, float rate){ idx++; e[idx].u = u, e[idx].v = v; e[idx].rate = rate; } int main() { while(cin >> n && n){ T++; memset(dis, 0, sizeof(dis)); dis[1] = 1; // get all currency name map<string, int> mp; for(int i = 1; i <= n; i++){ string currency; cin >> currency; mp[currency] = i; } cin >> m; // read exchange data string currency1, currency2; float rate; idx = 0; for(int i = 1; i <= m; i++){ cin >> currency1 >> rate >> currency2; int c1 = mp[currency1], c2 = mp[currency2]; addedge(c1, c2, rate); } // bellman-ford for(int k = 1; k <= n; k++){ for(int i = 1; i <= m; i++){ int u = e[i].u, v = e[i].v; float w = e[i].rate; if(dis[u] * w > dis[v]) dis[v] = dis[u] * w; } } // check if result is legal bool res = true; for(int i = 1; i <= m; i++){ int u = e[i].u, v = e[i].v; float w = e[i].rate; if(dis[u] * w - 1e-7 > dis[v]){ res = false; break; } } cout << "Case " << T << ": " << (res ? "No" : "Yes") << endl; } return 0; }
思路:反向建图。花费要用long long类型,否则会WA。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 1e6 + 5; int T, P, Q; long long dis[maxn], rdis[maxn]; int head[maxn], rhead[maxn]; bool vis[maxn], rvis[maxn]; struct Edge{ int v, w, next; } e[maxn], re[maxn]; int idx, ridx; void addedge(int u, int v, int w, Edge *e, int *head, int &idx){ idx++; e[idx].v = v, e[idx].w = w; e[idx].next = head[u]; head[u] = idx; } void spfa(Edge* e, int* head, long long* dis, int idx, bool *vis){ queue<int> q; q.push(1); vis[1] = true; while(q.size()){ int u = q.front(); q.pop(); vis[u] = false; for(int i = head[u]; i; i = e[i].next){ int v = e[i].v, w = e[i].w; if(dis[v] > dis[u] + w){ dis[v] = dis[u] + w; if(!vis[v]){ vis[v] = true; q.push(v); } } } } } void init(){ idx = 0; memset(dis, 0x3f, sizeof(dis)); memset(head, 0, sizeof(head)); memset(rdis, 0x3f, sizeof(rdis)); memset(rhead, 0, sizeof(rhead)); dis[1] = rdis[1] = 0; } inline int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar(); return s * w; } int main() { T = read(); while(T--){ init(); P = read(), Q = read(); for(int i = 1; i <= Q; i++){ int u, v, w; u = read(), v = read(), w = read(); addedge(u, v, w, e, head, idx); addedge(v, u, w, re, rhead, ridx); } spfa(e, head, dis, idx, vis); spfa(re, rhead, rdis, ridx, rvis); long long res = 0; for(int i = 1; i <= P; i++) res += dis[i] + rdis[i]; cout << res << endl; } return 0; }
思路:差分约束。忘记调dijkstra函数了,debug好长时间和(;´д`)ゞ,最后还是借鉴了他人的代码发现了问题。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; typedef pair<int, int> P; const int INF = 0x3f3f3f3f; const int maxn = 3e4 + 5; const int maxm = 15e4 + 5; int N, M; int head[maxn], dis[maxn]; int idx; struct Edge{ int v, w, next; } e[maxm]; void addedge(int u, int v, int w){ e[++idx] = {v, w, head[u]}; head[u] = idx; } void dijkstra(){ memset(dis, 0x3f, sizeof(dis)); dis[1] = 0; priority_queue<P, vector<P>, greater<P> > q; q.push(P(0, 1)); while(q.size()){ P np = q.top(); q.pop(); int u = np.second; if(dis[u] < np.first) continue; for(int i = head[u]; i; i = e[i].next){ int v = e[i].v, w = e[i].w; if(dis[v] > dis[u] + w){ dis[v] = dis[u] + w; q.push(P(dis[v], v)); } } } } int read(){ int x = 0, s = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') s = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ x = (x << 1) + (x << 3) + (ch ^48); ch = getchar(); } return x * s; } int main() { N = read(), M = read(); for(int i = 1; i <= M; i++){ int u, v, w; u = read(), v = read(), w = read(); addedge(u, v, w); } dijkstra(); cout << dis[N] << endl; return 0; }
思路:最短路,建图麻烦,题目中距离的描述不清晰,取整方式也没说。暂时不想写。
思路:题目好蠢,下一题。
思路:每个点最多需要通过一次即可。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; typedef pair<int, int> P; const int INF = 0x3f3f3f3f; const int maxn = 105; int N, A, B; int head[maxn], dis[maxn]; bool vis[maxn]; int idx; struct Edge{ int v, w, next; } e[maxn * maxn]; void addedge(int u, int v, int w){ e[++idx] = {v, w, head[u]}; head[u] = idx; } void spfa(int A){ memset(dis, 0x3f, sizeof(dis)); dis[A] = 0; queue<int> q; q.push(A); vis[A] = true; while(q.size()){ int u = q.front(); q.pop(); vis[u] = false; for(int i = head[u]; i; i = e[i].next){ int v = e[i].v, w = e[i].w; if(dis[v] > dis[u] + w){ dis[v] = dis[u] + w; if(!vis[v]){ vis[v] = true; q.push(v); } } } } } int main() { scanf("%d%d%d", &N, &A, &B); for(int u = 1; u <= N; u++){ int k, v; scanf("%d%d", &k, &v); addedge(u, v, 0); for(int j = 1; j < k; j++){ scanf("%d", &v); addedge(u, v, 1); } } spfa(A); cout << (dis[B] == 0x3f3f3f3f ? -1 : dis[B]) << endl; return 0; }
思路:题目描述真是一言难尽,下一题。
HDU4725 The Shortest Path in Nya Graph
思路:结点分多层,如果直接把相邻层结点连接,会超内存限制。一个简单的解决方案是增加一个中间结点代表某一层,然后建图。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 1e5 + 5; // head[n + i] represents the node of i-th layer to i+1-th layer int head[maxn * 2], dis[maxn * 2]; bool vis[maxn * 2]; int idx; struct Edge{ int v, w, next; } e[maxn * 5]; void addedge(int u, int v, int w){ e[++idx] = {v, w, head[u]}; head[u] = idx; } void spfa(){ memset(dis, 0x3f, sizeof(dis)); dis[1] = 0; queue<int> q; q.push(1); vis[1] = true; while(q.size()){ int u = q.front(); q.pop(); vis[u] = false; for(int i = head[u]; i; i = e[i].next){ int v = e[i].v, w = e[i].w; if(dis[v] > dis[u] + w){ dis[v] = dis[u] + w; if(!vis[v]){ q.push(v); vis[v] = true; } } } } } void init(){ idx = 0; memset(head, 0, sizeof(head)); } int main() { int T; int n, m, c; scanf("%d", &T); for(int t = 1; t <= T; t++){ init(); scanf("%d%d%d", &n, &m, &c); // add layer edge for(int i = 1; i <= n; i++){ int layer; scanf("%d", &layer); addedge(n + layer, i, 0); if(layer > 1) addedge(i, n + layer - 1, c); if(layer < n) addedge(i, n + layer + 1, c); } // add extra edge for(int i = 1; i <= m; i++){ int u, v, w; scanf("%d%d%d", &u, &v, &w); addedge(u, v, w); addedge(v, u, w); } spfa(); cout << "Case #" << t << ": " << (dis[n] == 0x3f3f3f3f ? -1 : dis[n]) << endl; } return 0; }
思路:多跑几次最短路。
思路:以前就做过的一道题,但是代码好像不是我的。把矩阵看作是联通图即可。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; #define INF 0x3f3f3f3f #define P pair<int, int> const int maxn = 303; int n; int C[maxn][maxn]; int vis[maxn], dis[maxn]; void spfa(int ss){ queue<int> s; for(int i = 1; i <= n; i++){ if(i==ss){ dis[i] = 0x3f3f3f3f; vis[i] = 0; } else{ dis[i] = C[ss][i]; vis[i] = 1; s.push(i); } } while(!s.empty()){ int u = s.front(); s.pop(); vis[u] = 0; for(int v = 1; v <= n; v++){ if(dis[v]>dis[u]+C[u][v]){ dis[v] = dis[u] + C[u][v]; if(vis[v]==0){ vis[v] = 1; s.push(v); } } } } } int main(){ while(~scanf("%d", &n)){ for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) scanf("%d", &C[i][j]); spfa(1); int dis1 = dis[1], dis2 = dis[n]; spfa(n); int dis3 = dis[n]; int output = min(dis2, dis1+dis3); printf("%d\n", output); } return 0; }
思路:差分约束。专题最后一题,代码不想写了,就到此结束吧。

浙公网安备 33010602011771号