2360: 【作】【基础】回家 Bessie Come Home
内存限制:128 MB
时间限制:1.000 S
评测方式:文本比较
命题人:
提交:8
解决:7
题目描述
现在是晚餐时间,而母牛们在外面分散的牧场中。
Farmer John 按响了电铃,所以她们开始向谷仓走去。 你的工作是要指出哪只母牛会最先到达谷仓(在给出的测试数据中,总会有且只有一只最快的母牛)。在挤奶的时候(晚餐前),每只母牛都在她自己的牧场上,一些牧场上可能没有母牛。
每个牧场由一条条道路和一个或多个牧场连接(可能包括自己)。有时,两个牧场(可能是字母相同的)之间会有超过一条道路相连。至少有一个牧场和谷仓之间有道路连接。因此,所有的母牛最后都能到达谷仓,并且母牛总是走最短的路径。当然,母牛能向着任意一方向前进,并且她们以相同的速度前进。牧场被标记为 和 ,在用大写字母表示的牧场中有一只母牛,小写字母中则没有。 谷仓的标记是 ,注意没有母牛在谷仓中。
注意 m 和 M 不是同一个牧场。
输入
第一行一个整数 (),表示连接牧场(谷仓)的道路的数目。
接下来 行,每行用空格分开的两个字母和一个正整数:被道路连接牧场的标号和道路的长度(道路长度均不超过 )。
输出
单独的一行包含二个项目:最先到达谷仓的母牛所在的牧场的标号,和这只母牛走过的路径的长度。
样例输入 复制
5
A d 6
B d 3
C e 9
d Z 8
e Z 3
样例输出 复制
B 11
提示
把 52 个牧场映射成节点(a..z→1..26,A..Y→27..51,谷仓 Z→52),从谷仓 Z 跑一遍 Dijkstra,再在带母牛的大写牧场 A..Y 里找距离最小的那个。
#include <bits/stdc++.h>
using namespace std;
/*
1.本题:求每只母牛(大写字母牧场)到谷仓Z的最短路
定义r[]存储:每个点来自哪个点
在更新更短路的时候,更新某个点来自的点
2.描述无向图,且要注意读入两个字母和长度,要自己构建邻接矩阵
牧场标记为a..z(1..26)、A..Y(27..51),谷仓Z(52)
3.两点之间可能有多条路径(包括字母相同的)
多条路的情况下,我们保留两点之间的最短路
*/
const int N = 55;
const int INF = 0x3f3f3f3f;
int a[N][N];//邻接矩阵
int d[N];//存储走到每个点的最短路径长度
bool f[N];//存储哪些点是确定求出最短路长度
int n = 52;//总节点数
//把字母转换成节点编号
int id(char c){
if(c >= 'a' && c <= 'z') return c - 'a' + 1; //a..z -> 1..26
return c - 'A' + 27; //A..Z -> 27..52
}
int main(){
int P;
cin>>P;
char x,y;
int len;
//读入P条道路
for(int i = 1;i <= P;i++){
cin>>x>>y>>len;
int x1 = id(x), y1 = id(y);
//如果没有读到边,或者边更短
//多条边的情况下保留最短边
if(a[x1][y1]==0 || len < a[x1][y1]){
a[x1][y1] = len;
a[y1][x1] = len;
}
}
int Z = id('Z');//谷仓是Z
//dijkstra:从谷仓Z出发求到每个点的最短路
memset(d,0x3f,sizeof(d));
d[Z] = 0;//谷仓的最短路径值可以确定
for(int i = 1;i <= n;i++){
int mi = -1;
//求没有确定的点的最小数下标
for(int j = 1;j <= n;j++){
if(!f[j] && (mi == -1 || d[j] < d[mi])){
mi = j;
}
}
//确定该点的路径是最短的
f[mi] = true;
//尝试mi可以去的点中,没有确定的点,是否有更短路
for(int j = 1;j <= n;j++){
if(!f[j]&&a[mi][j]!=0&&d[mi]+a[mi][j]<d[j]){
d[j] = d[mi] + a[mi][j];
}
}
}
//找距离谷仓最近的带母牛的大写牧场(A..Y = 27..51)
int ans = 0;
for(int i = 27;i <= 51;i++){
if(ans == 0 || d[i] < d[ans]){
ans = i;
}
}
printf("%c %d\n",'A' + ans - 27, d[ans]);
return 0;
}
#include <bits/stdc++.h>
using namespace std;
struct edge{
int from, to, len, next;
};
const int MAXEDGE = 20005;
edge a[MAXEDGE];
int k = 0;
int pre[60]; //最多52个点,开大一点
int s; //起点是Z
const int INF = 0x3f3f3f3f;
int d[60];
bool f[60];
void add(int u,int v,int l){
k++;
a[k].from = u;
a[k].to = v;
a[k].len = l;
a[k].next = pre[ u ];
pre[ u ] = k;
}
void dijkstra(int n){
memset(d,0x3f,sizeof(d));
memset(f,0,sizeof(f));
d[ s ] = 0;
for(int i = 1; i <= n; i++){
int mi = -1;
for(int j = 1; j <= 52; j++){
if(!f[j] && (mi == -1 || d[j] < d[mi])){
mi = j;
}
}
f[mi] = true;
for(int j = pre[mi]; j != 0; j = a[j].next){
int to = a[j].to;
if(!f[to] && d[mi] + a[j].len < d[to]){
d[to] = d[mi] + a[j].len;
}
}
}
}
//字母转编号函数
int char2num(char c){
if(c >= 'A' && c <= 'Z'){
return c - 'A' + 1;
}else{
return c - 'a' + 27;
}
}
int main(){
int P;
cin >> P;
for(int i = 1; i <= P; i++){
char ch1,ch2;
int w;
cin >> ch1 >> ch2 >> w;
int u = char2num(ch1);
int v = char2num(ch2);
add(u, v, w);
add(v, u, w); //双向边
}
s = char2num('Z'); //起点:谷仓Z
dijkstra(52); //总节点最多52个
//遍历A~Y(编号1~25)找最小距离
char ans_char;
int min_dist = INF;
for(int c = 1; c <= 25; c++){
if(d[ c ] < min_dist){
min_dist = d[ c ];
ans_char = 'A' + c - 1;
}
}
cout << ans_char << " " << min_dist;
return 0;
}
思路回顾
-
谷仓是
Z,以 Z 作为起点跑 SPFA,求所有牧场到 Z 的最短距离 -
字母映射成数字编号:大写 A~Z,小写 a~z,一共 52 个点
-
A→1,B→2 …Z→26 -
a→27,b→28 …z→52
-
-
母牛只在大写
A~Y(编号 1~25),遍历这 25 个点,找到距离最小的那个 -
道路是双向边,
add(u,v,w); add(v,u,w);
#include <bits/stdc++.h>
using namespace std;
struct edge{
int from,to,len,next;
};
edge a[200010];
int n,e;
int k;
int pre[200010];
int d[200010];
queue<int> q;
bool f[200010];
void add(int u,int v,int l){
k++;
a[k].from = u;
a[k].to = v;
a[k].len = l;
a[k].next = pre[ u ];
pre[ u ] = k;
}
void spfa(int s){
memset(d,0x3f,sizeof(d));
d[ s ] = 0;
q.push(s);
f[ s ] = true;//入队标记
while(!q.empty()){
int h = q.front();
for(int i = pre[h];i != 0;i = a[i].next){
int to = a[i].to;
if(d[h] + a[i].len < d[to]){
d[to] = d[h] + a[i].len;
if(!f[to]){
q.push(to);
f[to] = true;//在队列中
}
}
}
f[h] = false;//出队标记
q.pop();
}
}
//字母转数字编号
int char2num(char c){
if(c >= 'A' && c <= 'Z'){
return c - 'A' + 1;
}else{
return c - 'a' + 27;
}
}
int main(){
int P;
cin >> P;
k = 0;
memset(pre, 0, sizeof pre); //清空邻接表头
for(int i = 1;i <= P;i++){
char ch1,ch2;
int w;
cin >> ch1 >> ch2 >> w;
int u = char2num(ch1);
int v = char2num(ch2);
add(u, v, w);
add(v, u, w); //双向边
}
int start = char2num('Z'); //起点是Z
spfa(start);
//在A~Y(1~25)找最小距离
char ans_c;
int min_dis = 0x3f3f3f3f;
for(int i = 1; i <= 25; i++){
if(d[i] < min_dis){
min_dis = d[i];
ans_c = 'A' + i - 1;
}
}
cout << ans_c << " " << min_dis;
return 0;
}