A1072跳转题目
一、题目大意
给你n个普通地点, m个可能设为加油站的地点,求m中能同时覆盖所有普通地点(到所有普通地点的最大距离不超过加油站的服务距离)的编号,有多个就按照到普通地点的最小距离较大、到所有普通地点的平均距离较小,较小编号排序选最优
二、分析
(1)通过第一个样例我们能看出来,n、m要一起跑最短路,但是计算m中可能为加油站的点x时,只用求x对1~n的距离
(2)输入中带有G1、G2这种的, 所以需要特殊处理,使n + 1号点表示G1、n + 2号点表示G2
(3)最终精确到小数点后1位不用+0.05直接.1lf就行,要不然最后一个测试点过不了,样例挺恶心的,我也是看了别人题解才知道这一点
三、代码
#include <bits/stdc++.h>
#define int long long
#define all(x) (x).begin(), (x).end()
#define len(x) (x).size()
#define endl '\n'
#define lowbit(x) ((x) & - (x))
//using namespace std;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int path[1111][1111];
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
//std::cout.precision(10);
int n, m, k, max;
std::cin >> n >> m >> k >> max;
memset(path, 0x3f, sizeof(path));
for(int i = 1; i <= n + m; i++)
path[i][i] = 0;//初始化自身距离,防止后续数据有锅出现自环
//后续节点我们都采用字符串输入,所以预处理一下对应的节点编号
std::map<std::string, int> find;
for(int i = 1; i <= n; i++) {
std::string s = "";
s += std::to_string(i);
find[s] = i;
}
for(int i = n + 1; i <= m + n; i++) {
std::string s = "G";
s += std::to_string(i - n);
find[s] = i;// G1对应n + 1
}
for(int i = 1; i <= k; i++) {
std::string u, v;
int x;
std::cin >> u >> v >> x;
path[find[u]][find[v]] = std::min(x, path[find[u]][find[v]]);
path[find[v]][find[u]] = std::min(x, path[find[v]][find[u]]);
}
struct Gas {
int id;
double min;
double avg;
bool operator < (const Gas temp) {//设置排序规则
if(this->min == temp.min && this->avg == temp.avg)
return this->id < temp.id;
if(this->min == temp.min)
return this->avg < temp.avg;
return this->min > temp.min;
}
};
std::vector<Gas> v;
auto dij = [&](int start) {//求start到其他所有点的最短路
std::vector<int> dist(n + m + 1, 0x3f3f3f3f), flag(n + m + 1, 0);
std::priority_queue<
std::pair<int, int>,
std::vector<std::pair<int, int>>,
std::greater<std::pair<int, int>>
> heap;//这里采用的是堆优化的dij,所以开个小根堆
//下面就是dij的板子
dist[start] = 0;
heap.push({0, start});
while(len(heap)) {
auto t = heap.top();
heap.pop();
int root = t.second;
int dis = t.first;
if(flag[root])
continue;
flag[root] = 1;
for(int i = 1; i <= n + m; i++) {
if(i == root)
continue;
if(path[root][i] == 0x3f3f3f3f)
continue;
if(dist[i] > dist[root] + path[root][i]) {
dist[i] = dist[root] + path[root][i];
heap.push({dist[i], i});
}
}
}
double sum = 0;
double min = 0x3f3f3f3f;
int ok = 1;
for(int i = 1; i <= n; i++) {
if(dist[i] > max)
ok = 0;
sum += dist[i];
min = std::min(min, dist[i] * 1.0);
}
if(ok) {//满足能覆盖所有普通点的可能点都记录下来
sum /= n;
Gas gas;
gas.id = start;
gas.min = min;
gas.avg = sum;
v.push_back(gas);
}
};
for(int i = n + 1; i <= m + n; i++) {//对m个可能点跑dij
dij(i);
}
if(len(v) == 0) {
std::cout << "No Solution";
} else {
std::sort(all(v));//排序取最优
printf("G%lld\n%.1lf %.1lf", v[0].id - n, v[0].min, v[0].avg);
}
return 0;
}
A1082跳转题目
一、题目大意
求起点到终点的最短距离的路径数、最短路径的大小、最大幸福值(路径点权和)、除起点的平均幸福值大小(向下取整),整个路径
二、分析
这题比较缝合,要处理输入,把字符串给离散化成整数编号,last维护到起点当前节点的上一节点,sum维护起点到当前节点的路径点权和,cnt维护起点到当前点的路径条数
三、代码
#include <bits/stdc++.h>
#define int long long
#define all(x) (x).begin(), (x).end()
#define len(x) (x).size()
#define endl '\n'
#define lowbit(x) ((x) & - (x))
//using namespace std;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int path[500][500];
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
//std::cout.precision(10);
std::map<std::string, int> find;//查找城市对应的节点编号
std::map<int, std::string> hash;//查找节点编号对应的城市
memset(path, 0x3f, sizeof(path));
int n, m;
std::cin >> n >> m;
for(int i = 1; i <= n; i++)
path[i][i] = 0;
std::vector<int> vue(n + 1);//存储幸福值
std::string st;
std::cin >> st;
find[st] = 1;
hash[1] = st;
vue[1] = 0;
for(int i = 2; i <= n; i++) {
std::string s;
std::cin >> s;
int x;
std::cin >> x;
find[s] = i;
hash[i] = s;
vue[i] = x;
}
for(int i = 1; i <= m; i++) {
std::string u, v;
int x;
std::cin >> u >> v >> x;
path[find[u]][find[v]] = std::min(x, path[find[u]][find[v]]);
path[find[v]][find[u]] = std::min(x, path[find[v]][find[u]]);
}
auto dij = [&](int start) {
std::vector<int> dist(n + 1, 0x3f3f3f3f), flag(n + 1, 0), cnt(n + 1, 0), sum(n + 1, 0), last(n + 1, 0);
std::priority_queue<
std::pair<int, int>,
std::vector<std::pair<int, int>>,
std::greater<std::pair<int, int>>
> heap;
初始化起点
dist[start] = 0;
cnt[start] = 1;
sum[start] = 0;
last[start] = -1;
heap.push({0, start});
while(len(heap)) {
auto t = heap.top();
heap.pop();
int root = t.second;
int res = t.first;
if(flag[root])
continue;
flag[root] = 1;
for(int i = 1; i <= n; i++) {
if(i == root)
continue;
if(path[root][i] == 0x3f3f3f3f)
continue;
if(dist[i] > dist[root] + path[root][i]) {//起点到当前点的最短路被更新
dist[i] = dist[root] + path[root][i];
cnt[i] = cnt[root];//继承root的路径条数
sum[i] = sum[root] + vue[i];//重置当前点的幸福感
last[i] = root;//当前点的上一节点为root
heap.push({dist[i], i});
} else if(dist[i] == dist[root] + path[root][i]) {//出现最短路大小相同的路径
cnt[i] += cnt[root];//那么到当前点的路径条数就增加cnt[root]条
if(sum[i] < sum[root] + vue[i]) {//能从这个root获得更大的幸福感
sum[i] = sum[root] + vue[i];
last[i] = root;//那么就让当前点从这个root过来
}
}
}
}
std::string end = "ROM";
std::vector<int> v;
for(int i = find[end]; i != -1; i = last[i]) {//回溯路径
v.push_back(i);
}
int ans = sum[find[end]] / (len(v) - 1);
std::cout << cnt[find[end]] << " " << dist[find[end]] << " " << sum[find[end]] << ' ' << ans << endl;
for(int i = len(v) - 1; i >= 0; i--) {
std::cout << hash[v[i]];
if(i != 0)
std::cout << "->";
}
};
dij(find[st]);
return 0;
}