ACM 实验室2020.10.03天梯赛练习*1
7-13 垃圾箱分布
题意:n个点,m个能当作起始点,k条边,起始点不能与n个点距离超过ds,求到n个点的最短距离最长的起始点
思路:跑m遍dijkstra即可,练习的时候时间不够没写完
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> PII; const int maxn = 1000 + 15; const double eps = 1e-9; int n, m, k, ds; vector<PII> v[maxn]; int dis[maxn]; bool vis[maxn]; priority_queue<PII, vector<PII>, greater<> > que; int dijkstra(int x) { memset(vis, false, sizeof(vis)); memset(dis, 0x3f, sizeof dis); dis[x] = 0; que.push(PII(0, x)); while (!que.empty()) { int point = que.top().second; que.pop(); if (vis[point]) continue; vis[point] = true; for (auto i:v[point]) { if (dis[i.first] > dis[point] + i.second) { dis[i.first] = dis[point] + i.second; que.push(PII(dis[i.first], i.first)); } } } int minn = 0x3f3f3f3f; for (int i = 1; i <= n; i++) { if (dis[i] > ds) return 0x3f3f3f3f; minn = min(minn, dis[i]); } return minn; } int main() { cin >> n >> m >> k >> ds; getchar(); for (int i = 0; i < k; i++) { char s; int a = 0, b = 0, c; scanf("%c", &s); if (s == 'G') { cin >> a; a += 1000; getchar(); } else { while (s != ' ') { a *= 10; a += s - '0'; scanf("%c", &s); } } scanf("%c", &s); if (s == 'G') { cin >> b; b += 1000; getchar(); } else { while (s != ' ') { b *= 10; b += s - '0'; scanf("%c", &s); } } cin >> c; getchar(); v[a].push_back(PII(b, c)); v[b].push_back(PII(a, c)); } int point = 0; int ansmin = -1; int ansavg = 0x3f3f3f3f; for (int i = 1001; i <= 1000 + m; i++) { double minn = dijkstra(i); if (minn == 0x3f3f3f3f) continue; if (ansmin < minn) { ansmin = minn; int avg = 0; for (int j = 1; j <= n; j++) avg += dis[j]; ansavg = avg; point = i; } else if (minn == ansmin) { int avg = 0; for (int j = 1; j <= n; j++) avg += dis[j]; if (ansavg > avg) { ansavg = avg; point = i; } } } if (point != 0) { cout << "G" << point - 1000 << endl; printf("%.1lf %.1lf\n", ansmin * 1.0, ansavg / (double) n); } else cout << "No Solution" << endl; return 0; }
7-15 地铁一日游
题意:n个点m段线路k为为计费距离限制,给m段线路后,q次询问,每次从x站出发,求能拍照的站点
思路:题目吧啦了一堆,无非是要说以下条件:
选某个车费中最远的(比如说,我花5块钱能到3个地方,那么选最远的)
路线的端点(注意!这里是指连通路线的端点)
用Floyed求最短路,每个站点都找到能拍照的站点,对每次查询都dfs一遍。
靠蒙和猜题意,慢慢写
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> PII; const int maxn = 200 + 5; const double eps = 1e-9; struct point { int vis = 0; int ends = 0; vector<int> res; } points[maxn]; int n, m, k; int mp[maxn][maxn]; void floyed() { for (int K = 1; K <= n; K++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (i != j && mp[i][j] > mp[i][K] + mp[K][j]) mp[i][j] = mp[i][K] + mp[K][j]; } void dfs(int x, int vis) { for (int i = 0; i < points[x].res.size(); i++) { int tmp = points[x].res[i]; if (points[tmp].vis != vis) { points[tmp].vis = vis; dfs(tmp, vis); } } } int main() { memset(mp, 0x3f, sizeof mp); cin >> n >> m >> k; for (int i = 0; i < m; i++) { int u, v, w; cin >> u; points[u].ends = 1; do { cin >> w >> v; if (w < mp[u][v]) { mp[u][v] = w; mp[v][u] = w; } u = v; } while (getchar() != '\n'); points[u].ends = 1; } floyed(); for (int i = 1; i <= n; i++) { map<int, int> mp1; for (int j = 1; j <= n; j++) if (mp[i][j] != 0x3f3f3f3f && mp[i][j] > mp1[mp[i][j] / k + 2]) mp1[mp[i][j] / k + 2] = mp[i][j]; for (int j = 1; j <= n; j++) if (mp[i][j] == mp1[mp[i][j] / k + 2] || (i != j && mp[i][j] != 0x3f3f3f3f && points[j].ends == 1)) points[i].res.push_back(j); } int q; cin >> q; for (int i = 1; i <= q; i++) { int start; cin >> start; points[start].vis = i; dfs(start, i); int first = true; for (int j = 1; j <= n; j++) if (points[j].vis == i) { if (!first) cout << " "; first = false; cout << j; } cout << endl; } return 0; }