Problem:
G: Quest of Merchant

ICPC で良い成績を収めるには修行が欠かせない．うさぎは ICPC で勝ちたいので，今日も修行をすることにした．

今日の修行は，街を駆け回り交易を行うことで，商売の力を手にしようというものである．

今後の修行のためにも，できるだけ多くの資金を稼ぎたい．

この世界は，東西南北方向の道路が等間隔に並んでいて，碁盤状になっている．唯一存在する市場の位置を (0, 0)，街には x 座標，y 座標が定まっている (座標が整数値の点が交差点に対応する)．うさぎは道路に沿ってのみ移動することができ，隣接する交差点間を移動するのに 1 分を要する．いくつかの交差点には街がある．交易では，街で商品を買い，市場にて販売することによって価格の差の分の利益を得る．

うさぎの初期資金は十分にあり，お金が足りないから商品が購入できない，といったことはない．だが，それぞれの商品には重さがあり，うさぎは重さの合計が W までの商品しか同時に持ち運ぶことができない．よって，街に商品を仕入れに行ったり市場に戻ったりを繰り返すことになる．場合によっては，複数の街で商品を購入してから市場に戻ることになるかもしれない．

街での商品の購入や，市場での商品の販売は一瞬で行えるものとする．また，街にある商品が品切れになってしまうことは有り得ず，無限に購入することが可能である．

うさぎは，今回売買を行おうとしている各商品の名前，1 個あたりの重さおよび販売価格と，各街の x 座標，y 座標および販売商品の名前と価格を，データにまとめた．うさぎは今，市場がある (0, 0) の位置にいる．プログラムを使って，制限時間 T 分の間にどれだけ稼ぐことが可能か調べたい．

Input

N M W T
S1 V1 P1
...
SM VM PM
L1 X1 Y1
R1,1 Q1,1
...
R1,L1 Q1,L1
...
LN XN YN
RN,1 QN,1
...
RN,LN QN,LN

N は街の数，M は商品の種類数である．Si, Vi, Pi (1 ≤ i ≤ M) はそれぞれ，i 番目の商品の名前，1 個あたりの重さ，1 個あたりの販売価格である．
街は 1 以上 N 以下の整数で表される．Lj, Xj, Yj (1 ≤ j ≤ N) はそれぞれ，街 j で売られている商品の種類数，街 j の x 座標，y 座標である．Rj,k, Qj,k (1 ≤ j ≤ N，1 ≤ k ≤ Lj) はそれぞれ，街 j で売られている k 番目の商品の名前，価格である．

1 ≤ N ≤ 7，1 ≤ M ≤ 7，1 ≤ W ≤ 10,000，1 ≤ T ≤ 10,000，1 ≤ Vi ≤ W，1 ≤ Pi ≤ 10,000，1 ≤ Lj ≤ M，-10,000 ≤ Xj ≤ 10,000，-10,000 ≤ Yj ≤ 10,000，1 ≤ Qj, k ≤ 10,000 を満たす．商品の名前はアルファベット小文字からなる長さが 1 以上 7 以下の文字列である．その他の値はすべて整数である．Si はすべて異なる．(Xj, Yj) として同一の組は複数回現れず，(Xj, Yj) = (0, 0) となることはない．
各 j に対して Rj, k はすべて異なり，各 Rj，k はいずれかの Si に一致する．

Output

うさぎが得られる最大の利益を 1 行に出力せよ．

Sample Input 1

2 2 100 20
alfalfa 10 10
carrot 5 10
1 1 6
carrot 4
1 -3 0
alfalfa 5

Sample Output 1

170

Sample Input 2

2 3 100 20
vim 10 10
emacs 5 10
vstudio 65 100
2 1 6
emacs 4
vstudio 13
3 -3 0
vim 5
emacs 9
vstudio 62

Sample Output 2

183

Solution in Rust (judge verdict: Accepted)

extern crate core;

use std::fmt;
use std::cmp::{max, min, Ordering};
use std::collections::{BinaryHeap, BTreeMap};
macro_rules! read_line{
    () => {{
        let mut line = String::new();
        std::io::stdin().read_line(&mut line).ok();
        line
    }};
    (delimiter: ' ') => {
        read_line!().split_whitespace().map(|x|x.to_string()).collect::<Vec<_>>()
    };
    (delimiter: $p:expr) => {
        read_line!().split($p).map(|x|x.to_string()).collect::<Vec<_>>()
    };
    (' ') => {
        read_line!(delimiter: ' ')
    };
    ($delimiter:expr) => {
        read_line!(delimiter: $delimiter)
    };
    (' '; $ty:ty) => {
        read_line!().split_whitespace().map(|x|x.parse::<$ty>().ok().unwrap()).collect::<Vec<$ty>>()
    };
    ($delimiter:expr; $ty:ty) => {
        read_line!($delimiter).into_iter().map(|x|x.parse::<$ty>().ok().unwrap()).collect::<Vec<$ty>>()
    };
}
macro_rules! let_all {
    ($($n:ident:$t:ty),*) => {
        let line = read_line!(delimiter: ' ');
        let mut iter = line.iter();
        $(let $n:$t = iter.next().unwrap().parse().ok().unwrap();)*
    };
}
#[derive(Copy, Clone, Eq, PartialEq, Default)]
struct Searched {
    serial: usize
}
impl Searched {
    fn new() -> Searched {
        Searched{serial: 0}
    }
    fn added(&self, target: usize) -> Searched {
        Searched{serial: self.serial | (1 << target)}
    }
    fn is_searched(&self, target: usize) -> bool {
        self.serial & (1 << target) != 0
    }
}
#[derive(Copy, Clone, Eq, PartialEq, Default)]
struct Coordinate {
    x: i32, y: i32
}
impl Coordinate {
    fn new(x: i32, y: i32) -> Coordinate {
        Coordinate{x: x, y: y}
    }
    fn manhattan_distance(&self, &other: &Self) -> i32 {
        (self.x - other.x).abs() + (self.y - other.y).abs()
    }
}
trait AbsoluteValue {
    fn abs(&self) -> Self;
}
impl AbsoluteValue for i32 {
    fn abs(&self) -> Self {
        if self < &0 {
            -*self
        }else {
            *self
        }
    }
}
struct ValueWithKey<K, V> {
    key: K, value: V,
}
impl <K, V> Ord for ValueWithKey<K, V> where K: Ord {
    fn cmp(&self, other: &Self) -> Ordering {
        self.key.cmp(&other.key)
    }
}
impl <K, V> PartialOrd for ValueWithKey<K, V> where K: PartialOrd {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.key.partial_cmp(&other.key)
    }
}
impl <K, V> PartialEq for ValueWithKey<K, V> where K: PartialEq {
    fn eq(&self, other: &Self) -> bool {
        self.key == other.key
    }
}
impl <K, V> Eq for ValueWithKey<K, V> where K: Eq {}
fn min_time_for_visit(ref town: &Vec<Coordinate>) -> Vec<i32> {
    let mut min_cost: Vec<Vec<i32>> = vec![vec![std::i32::MAX; town.len()]; 1 << town.len()];
    let start = Coordinate::new(0, 0);
    let mut queue: BinaryHeap<ValueWithKey<i32, (usize, Searched)>> = BinaryHeap::new();
    for i in 0 .. town.len() {
        min_cost[Searched::new().added(i).serial][i] = start.manhattan_distance(&town[i]);
        queue.push(ValueWithKey{key: start.manhattan_distance(&town[i]), value: (i, Searched::new().added(i))});
    }
    while let Some(ValueWithKey{key: cost, value:(from, searched)}) = queue.pop() {
        if min_cost[searched.serial][from] == cost {
            for to in 0 .. town.len() {
                if !searched.is_searched(to) && min_cost[searched.added(to).serial][to] > cost + town[from].manhattan_distance(&town[to]) {
                    min_cost[searched.added(to).serial][to] = cost + town[from].manhattan_distance(&town[to]);
                    queue.push(ValueWithKey{key: min_cost[searched.added(to).serial][to], value: (to, searched.added(to))});
                }
            }
        }
    }
    let mut ret = Vec::<i32>::with_capacity(1 << town.len());
    for &ref vec in &min_cost {
        let mut min:i32 = std::i32::MAX;
        for i in 0 .. town.len() {
            if vec[i] < min - town[i].manhattan_distance(&start){
                min = vec[i] + town[i].manhattan_distance(&start);
            }
        }
        ret.push(min);
    }
    ret
}

struct GoodsInfo {
    weight: usize, value: usize
}
#[derive(Copy, Clone)]
struct TradeInfo {
    goods_id: usize, benefit: usize
}
fn main() {
    let_all!(n: usize, m: usize, w: usize, t: usize);
    let mut goods_to_usize = BTreeMap::<String, usize>::new();
    let mut goods = Vec::with_capacity(m);
    for i in 0 .. m {
        let_all!(name: String, weight: usize, value: usize);
        goods_to_usize.insert(name, i);
        goods.push(GoodsInfo{weight: weight, value: value});
    }
    let goods_to_usize = goods_to_usize;
    let goods = goods;
    let mut town_coordinate = Vec::with_capacity(n);
    let mut town_info = vec![Vec::new(); n];
    for i in 0 .. n {
        let_all!(l: usize, x: i32, y: i32);
        town_coordinate.push(Coordinate{x: x, y: y});
        for _ in 0 .. l {
            let_all!(r: String, q: usize);
            if let Some(&g) = goods_to_usize.get(&r) {
                if goods[g].value > q {
                    town_info[i].push(TradeInfo { goods_id: g, benefit: goods[g].value - q});
                }
            }else {
                unreachable!()
            }
        }
    }
    let town_coordinate = town_coordinate;
    let town_info = town_info;
    let visit_time = min_time_for_visit(&town_coordinate);
    let mut visit_benefit = vec![0; 1 << n];
    for state in 0 .. visit_time.len() {
        let mut max_earn: Vec<i32> = vec![0; m];
        for i in 0 .. n {
            if state & (1 << i) != 0 {
                for &g in &town_info[i] {
                    if max_earn[g.goods_id] < g.benefit as i32 {
                        max_earn[g.goods_id] = g.benefit as i32;
                    }
                }
            }
        }
        let mut max_earn_by_weight = vec![-1 as i64; w + 1];
        max_earn_by_weight[0] = 0;
        let mut max = 0;
        for i in 0 .. w + 1 {
            if max_earn_by_weight[i] != -1 {
                if max < max_earn_by_weight[i] {
                    max = max_earn_by_weight[i];
                }
                for g in 0 .. m {
                    if max_earn[g] > 0 && goods[g].weight + i <= w && max_earn_by_weight[i + goods[g].weight] < max_earn[g] as i64 + max_earn_by_weight[i] {
                        max_earn_by_weight[i + goods[g].weight] = max_earn[g] as i64 + max_earn_by_weight[i];
                    }
                }
            }
        }
        visit_benefit[state] = max;
    }
    let visit_benefit = visit_benefit;
    let mut max_benefit_by_time = vec![-1; t + 1];
    max_benefit_by_time[0] = 0;
    let mut max = 0;
    for i in 0 .. t + 1 {
        if max_benefit_by_time[i] != -1 {
            if max < max_benefit_by_time[i] {
                max = max_benefit_by_time[i];
            }
            for state in 0 .. visit_time.len() {
                if visit_time[state] < max_benefit_by_time.len() as i32 && i as i32 + visit_time[state] < max_benefit_by_time.len() as i32 && max_benefit_by_time[i + visit_time[state] as usize] < max_benefit_by_time[i] + visit_benefit[state] {
                    max_benefit_by_time[i + visit_time[state] as usize] = max_benefit_by_time[i] + visit_benefit[state];
                }
            }
        }
    }
    println!("{}", max);
}