地图查询(Do You Know The Way to San Jose?, ACM/ICPC World Finals 1997, UVa511)rust解法

有n张地图(已知名称和某两个对角线端点的坐标)和m个地名(已知名称和坐标),还有q个查询。每张地图都是边平行于坐标轴的矩形,比例定义为高度除以宽度的值。每个查询包含一个地名和详细等级i。面积相同的地图总是属于同一个详细等级。假定包含此地名的地图中一共有k种不同的面积,则合法的详细等级为1~k(其中1最不详细,k最详细,面积越小越详细)。如果详细等级i的地图不止一张,则输出地图中心和查询地名最接近的一张;如果还有并列的,地图长宽比应尽量接近0.75(这是Web浏览器的比例);如果还有并列,查询地名和地图右下角的坐标应最远(对应最少的滚动条移动);如果还有并列,则输出x坐标最小的一个。如果查询的地名不存在或者没有地图包含它,或者i超过包含它的地图的最大详细等级,应报告查询非法(并输出包含它的最详细地图名称,如果存在)。

样例:
输入

MAPS
BayArea -6.0 12.0 -11.0 5.0
SantaClara 4.0 9.0 -3.5 2.5
SanJoseRegion -3.0 10.0 11.0 3.0
CenterCoast -5.0 11.0 1.0 -8.0
SanMateo -5.5 4.0 -12.5 9.0
NCalif -13.0 -7.0 13.0 15.0
LOCATIONS
Monterey -4.0 2.0
SanJose -1.0 7.5
Fresno 7.0 0.1
SanFrancisco -10.0 8.6
SantaCruz -4.0 2.0
SanDiego 13.8 -19.3
REQUESTS
SanJose 3
SanFrancisco 2
Fresno 2
Stockton 1
SanDiego 2
SanJose 4
SantaCruz 3
END

输出

SanJose at detail level 3 using SanJoseRegion
SanFrancisco at detail level 2 using BayArea
Fresno at detail level 2 no map at that detail level; using NCalif
Stockton at detail level 1 unknown location
SanDiego at detail level 2 no map contains that location
SanJose at detail level 4 using SantaClara
SantaCruz at detail level 3 no map at that detail level; using CenterCoast

解法:

use std::{collections::HashMap, io};
#[derive(Debug)]
struct Map {
    name: String,
    coord1: (f64, f64),
    coord2: (f64, f64),
    area: f64,
    mid_coord: (f64, f64),
    ratio: f64,
}
impl Map {
    fn contain(&self, coord: (f64, f64)) -> bool {
        let minx = self.coord1.0.min(self.coord2.0);
        let maxx = self.coord1.0.max(self.coord2.0);
        let miny = self.coord1.1.min(self.coord2.1);
        let maxy = self.coord1.1.max(self.coord2.1);
        if coord.0 >= minx && coord.0 <= maxx && coord.1 >= miny && coord.1 <= maxy {
            true
        } else {
            false
        }
    }
    fn mid_dist(&self, coord: (f64, f64)) -> f64 {
        (self.mid_coord.0 - coord.0).powf(2.0) + (self.mid_coord.1 - coord.1).powf(2.0)
    }
    fn rb_dist(&self, coord: (f64, f64)) -> f64 {
        let r = self.coord1.0.max(self.coord2.0);
        let b = self.coord1.1.min(self.coord2.1);
        (r - coord.0) * (r - coord.0) + (b - coord.1) * (b - coord.1)
    }
}

#[derive(Debug)]
struct Request {
    name: String,
    detail_level: usize,
}
fn main() {
    let mut buf = String::new();
    io::stdin().read_line(&mut buf).unwrap();
    let mut maps: Vec<Map> = vec![];
    loop {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        if buf.trim() == "LOCATIONS" {
            break;
        }
        let mut it = buf.split_whitespace();
        let name = it.next().unwrap();
        let v: Vec<f64> = it.map(|x| x.parse().unwrap()).collect();
        let coord1 = (v[0], v[1]);
        let coord2 = (v[2], v[3]);
        maps.push(Map {
            name: name.to_string(),
            coord1: coord1,
            coord2: coord2,
            area: (coord1.0 - coord2.0).abs() * (coord1.1 - coord2.1).abs(),
            mid_coord: ((coord1.0 + coord2.0) / 2.0, (coord1.1 + coord2.1) / 2.0),
            ratio: (coord1.0 - coord2.0).abs() / (coord1.1 - coord2.1).abs(),
        });
    }

    let mut location_maps: HashMap<String, Vec<&Map>> = HashMap::new();
    loop {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        if buf.trim() == "REQUESTS" {
            break;
        }
        let mut it = buf.split_whitespace();
        let name = it.next().unwrap();
        let v: Vec<f64> = it.map(|x| x.parse().unwrap()).collect();
        let coord = (v[0], v[1]);
        let mut in_maps: Vec<&Map> = vec![];
        for map in maps.iter() {
            if map.contain(coord) {
                in_maps.push(map);
            }
        }
        in_maps.sort_by(|a, b| {
            if a.area != b.area {
                b.area.partial_cmp(&a.area).unwrap()
            } else if a.mid_dist(coord) != b.mid_dist(coord) {
                a.mid_dist(coord).partial_cmp(&b.mid_dist(coord)).unwrap()
            } else if a.ratio != b.ratio {
                (a.ratio - 0.75)
                    .abs()
                    .partial_cmp(&(b.ratio - 0.75).abs())
                    .unwrap()
            } else if a.rb_dist(coord) != b.rb_dist(coord) {
                b.rb_dist(coord).partial_cmp(&a.rb_dist(coord)).unwrap()
            } else {
                a.coord1
                    .0
                    .min(a.coord2.0)
                    .partial_cmp(&b.coord1.0.min(b.coord2.0))
                    .unwrap()
            }
        });
        location_maps.insert(name.to_string(), in_maps);
    }

    let mut requests: Vec<Request> = vec![];
    loop {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        if buf.trim() == "END" {
            break;
        }
        let mut it = buf.split_whitespace();
        let name = it.next().unwrap();
        let detail_level: usize = it.next().unwrap().parse().unwrap();
        requests.push(Request {
            name: name.to_string(),
            detail_level,
        });
    }
    
    for r in requests.iter() {
        let name = &r.name;
        let detail_level = r.detail_level;
        print!("{} at detail level {} ", name, detail_level);
        if let Some(v) = location_maps.get(name) {
            if v.len() == 0 {
                println!("no map contains that location");
            } else {
                let mut level = 1;
                for j in 0..v.len() {
                    if level == detail_level {
                        println!("using {}", v[j].name);
                        break;
                    }
                    if j + 1 < v.len() && v[j].area != v[j + 1].area {
                        level += 1;
                    }
                }
                if level != detail_level {
                    println!(
                        "no map at that detail level; using {}",
                        v.last().unwrap().name
                    );
                }
            }
        } else {
            println!("unknown location");
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值