# jerry_fuyi

Working out everything from the first principles.

## PAT甲级题分类汇编——图

 题号 标题 分数 大意 时间 1072 Gas Station 30 最短距离最大，距离不超限 200ms 1076 Forwards on Weibo 30 一定层数的转发计数 3000ms 1079 Total Sales of Supply Chain 25 计算供应链总销售额 250ms 1087 All Roads Lead to Rome 30 复杂权重的最短路径问题 200ms 1090 Highest Price in Supply Chain 25 供应链最高价格 200ms 1091 Acute Stroke 30 超过阈值的空间体积之和 600ms

30分题肯定要做，这次就只做4道30分题：1072、1076、1087和1091。

1072：

  1 #include <iostream>
2 #include <iomanip>
3 #include <sstream>
4 #include <vector>
5 #include <queue>
6 #include <limits>
7
9 {
11         : dest(dest), dist(dist) { }
12     int dest;
13     int dist;
14 };
15
16 struct Node
17 {
18     int dist = std::numeric_limits<int>::max();
20 };
21
22 struct Coll
23 {
24     Coll(int index, int dist)
25         : index(index), dist(dist) { }
26     int index;
27     int dist;
28 };
29
30 struct Comp
31 {
32     static void init(std::vector<Node>& _nodes)
33     {
34         nodes = &_nodes;
35     }
36     static std::vector<Node>* nodes;
37     bool operator()(Coll i, Coll j)
38     {
39         return (*nodes)[i.index].dist > (*nodes)[j.index].dist;
40     }
41 };
42
43 std::vector<Node>* Comp::nodes = nullptr;
44
45 int get_node(int _offset)
46 {
47     std::string s;
48     std::stringstream ss;
49     std::cin >> s;
50     ss << s;
51     if (s[0] == 'G')
52     {
53         ss.get();
54         int i;
55         ss >> i;
56         --i;
57         i += _offset;
58         return i;
59     }
60     else
61     {
62         int i;
63         ss >> i;
64         --i;
65         return i;
66     }
67 }
68
69 int main()
70 {
71     int num_house, num_station, num_road, range;
72     std::cin >> num_house >> num_station >> num_road >> range;
73     std::vector<Node> nodes(num_house + num_station);
74     Comp::init(nodes);
75     for (int i = 0; i != num_road; ++i)
76     {
77         auto n0 = get_node(num_house), n1 = get_node(num_house);
78         int dist;
79         std::cin >> dist;
82     }
83     int best = -1;
84     int minimum = 0;
85     int total = std::numeric_limits<int>::max();
86     auto house_begin = nodes.begin();
87     auto house_end = nodes.begin() + num_house;
88     auto station_begin = nodes.begin() + num_house;
89     auto station_end = nodes.end();
90     for (auto station = station_begin; station != station_end; ++station)
91     {
92         std::priority_queue<Coll, std::vector<Coll>, Comp> queue;
93         for (auto& node : nodes)
94             node.dist = std::numeric_limits<int>::max();
95         station->dist = 0;
96         queue.emplace(station - nodes.begin(), 0);
97         while (!queue.empty())
98         {
99             auto coll = queue.top();
100             queue.pop();
101             auto& node = nodes[coll.index];
102             if (node.dist != coll.dist)
103                 continue;
104             for (const auto& r : node.roads)
105             {
106                 if (node.dist + r.dist < nodes[r.dest].dist)
107                 {
108                     nodes[r.dest].dist = node.dist + r.dist;
109                     queue.emplace(r.dest, nodes[r.dest].dist);
110                 }
111             }
112         }
113         int m = std::numeric_limits<int>::max();
114         int t = 0;
116         for (auto house = house_begin; house != house_end; ++house)
117         {
118             if (house->dist > range)
120             t += house->dist;
121             if (house->dist < m)
122                 m = house->dist;
123         }
125             continue;
126         if (m > minimum)
127         {
128             minimum = m;
129             best = station - nodes.begin();
130             total = t;
131         }
132         else if (m == minimum && t < total)
133         {
134             best = station - nodes.begin();
135             total = t;
136         }
137     }
138     if (best == -1)
139     {
140         std::cout << "No Solution";
141         return 0;
142     }
143     best = best - num_house + 1;
144     std::cout << 'G' << best << std::endl;
145     std::cout.setf(std::ios::fixed);
146     std::cout << std::setprecision(1);
147     std::cout << (double)minimum << ' ' << (double)total / num_house;
148 }

Dijkstra算法的时间复杂度关键取决于“找到距离已收集顶点最近的顶点”这步操作的复杂度。线性肯定是不好的，用优先队列是更好的方法。然而，当你把一个顶点加入到队列中以后，在它弹出之前，这个顶点的距离可能变得更近，即会改变它在堆中应该放的位置，为此需要重排，这样时间复杂度就不划算了。我的新方法是，在优先队列中存储结构体，包括顶点下标与插入优先队列时它的距离。弹出时，将这个距离与顶点对象中维护的距离相比较，如果不相等，说明这个弹出已经过时了，只是之前受限于结构无法删除，但现在可以忽略。由于优先队列以结构体中的距离为键值，此顶点在之前肯定已经被处理过了，所以可以名正言顺地忽略它。这样就可以不需要排序、查找等乱七八糟操作，同时顶点对象中也不再需要表示是否已收集的变量了。

1087：

  1 #include <iostream>
2 #include <string>
3 #include <vector>
4 #include <queue>
5 #include <map>
6 #include <limits>
7
8 struct Route
9 {
10     Route() = default;
11     Route(int dest, int dist)
12         : dest(dest), dist(dist) { }
13     int dest;
14     int dist;
15 };
16
17 struct City
18 {
19     std::string name;
20     std::vector<Route> routes;
21     int happiness;
22     int dist = std::numeric_limits<int>::max();
23     std::vector<std::vector<int>> paths;
24 };
25
26 struct Collect
27 {
28     Collect(int dest, int dist)
29         : dest(dest), dist(dist) { }
30     int dest;
31     int dist;
32 };
33
34 struct Comparator
35 {
36     static void init(std::vector<City>& _cities)
37     {
38         cities = &_cities;
39     }
40     static std::vector<City>* cities;
41     bool operator()(const Collect& lhs, const Collect& rhs)
42     {
43         return (*cities)[lhs.dest].dist > (*cities)[rhs.dest].dist;
44     }
45 };
46
47 std::vector<City>* Comparator::cities = nullptr;
48
49 int main()
50 {
51     int num_cities, num_routes;
52     std::cin >> num_cities >> num_routes;
53     std::vector<City> cities(num_cities);
54     std::cin >> cities[0].name;
55     std::map<std::string, int> city_map;
56     for (int i = 1; i != num_cities; ++i)
57     {
58         std::cin >> cities[i].name;
59         std::cin >> cities[i].happiness;
60         city_map[cities[i].name] = i;
61     }
62     for (int i = 0; i != num_routes; ++i)
63     {
64         std::string n0, n1;
65         std::cin >> n0 >> n1;
66         auto i0 = city_map[n0], i1 = city_map[n1];
67         int dist;
68         std::cin >> dist;
69         cities[i0].routes.emplace_back(i1, dist);
70         cities[i1].routes.emplace_back(i0, dist);
71     }
72     Comparator::init(cities);
73     cities[0].dist = 0;
74     cities[0].paths.resize(1);
75     std::priority_queue<Collect, std::vector<Collect>, Comparator> queue;
76     queue.emplace(0, 0);
77     while (!queue.empty())
78     {
79         auto col = queue.top();
80         queue.pop();
81         auto& city = cities[col.dest];
82         if (city.name == "ROM")
83             break;
84         if (city.dist != col.dist)
85             continue;
86         for (const auto& r : city.routes)
87         {
88             auto& target = cities[r.dest];
89             if (city.dist + r.dist < target.dist)
90             {
91                 target.dist = city.dist + r.dist;
92                 target.paths = city.paths;
93                 for (auto& p : target.paths)
94                     p.push_back(col.dest);
95                 queue.emplace(r.dest, target.dist);
96             }
97             else if (city.dist + r.dist == target.dist)
98             {
99                 for (auto p : city.paths)
100                 {
101                     p.push_back(col.dest);
102                     target.paths.push_back(std::move(p));
103                 }
104             }
105         }
106     }
107     auto& rome = cities[city_map["ROM"]];
108     std::cout << rome.paths.size() << ' ' << rome.dist << ' ';
109     int happiness = 0;
110     int count = 0;
111     int recommended;
112     for (auto p = rome.paths.begin(); p != rome.paths.end(); ++p)
113     {
114         int h = 0;
115         for (int i : *p)
116             h += cities[i].happiness;
117         if (h > happiness)
118         {
119             happiness = h;
120             count = p->size();
121             recommended = p - rome.paths.begin();
122         }
123         else if (h == happiness && p->size() < count)
124         {
125             count = p->size();
126             recommended = p - rome.paths.begin();
127         }
128     }
129     happiness += rome.happiness;
130     std::cout << happiness << ' ' << happiness / (count ? count : 1) << std::endl;
131     for (int i : rome.paths[recommended])
132         std::cout << cities[i].name << "->";
133     std::cout << "ROM" << std::endl;
134 }

1076：

3000ms真的吓到我了，啥题需要3000ms呢？怀着忐忑的心情我做完了这道题，跑出来140ms，而且我用的是C++的输入输出。因此我有理由相信这道题本应是300ms。

 1 #include <iostream>
2 #include <vector>
3 #include <queue>
4
5 struct User
6 {
7     std::vector<int> fans;
8     int layer;
9     bool forward;
10 };
11
12 int main()
13 {
14     int num_user, layer;
15     std::cin >> num_user >> layer;
16     std::vector<User> users(num_user);
17     for (int i = 0; i != num_user; ++i)
18     {
19         auto& u = users[i];
20         int count;
21         std::cin >> count;
22         for (int j = 0; j != count; ++j)
23         {
24             int t;
25             std::cin >> t;
26             --t;
27             users[t].fans.push_back(i);
28         }
29     }
30     int num_query;
31     std::cin >> num_query;
32     for (int i = 0; i != num_query; ++i)
33     {
34         int t;
35         std::cin >> t;
36         --t;
37         for (auto& u : users)
38             u.layer = 0, u.forward = false;
39         users[t].forward = true;
40         int count = 0;
41         std::queue<int> queue;
42         queue.push(t);
43         while (!queue.empty())
44         {
45             auto index = queue.front();
46             auto& user = users[index];
47             queue.pop();
48             for (int i : user.fans)
49             {
50                 auto& fan = users[i];
51                 if (!fan.forward)
52                 {
53                     //std::cout << i << ' ';
54                     fan.forward = true;
55                     ++count;
56                     fan.layer = user.layer + 1;
57                     if (fan.layer < layer)
58                         queue.push(i);
59                 }
60             }
61         }
62         std::cout << count << std::endl;
63     }
64 }

1091：

  1 #include <iostream>
2 #include <cstdio>
3 #include <queue>
4
5 struct Unit
6 {
8     bool collected = false;
9 };
10
11 struct Point
12 {
13     Point()
14         : Point(0, 0, 0) { }
15     Point(int x, int y, int z)
16         : x(x), y(y), z(z) { }
17     int x;
18     int y;
19     int z;
20 };
21
22 class Brain
23 {
24 public:
25     Brain(Point p)
26         : size(p)
27     {
28         data = new Unit[size.x * size.y * size.z];
29     }
30     ~Brain()
31     {
32         delete[] data;
33     }
34     Brain(const Brain&) = delete;
35     Brain(Brain&&) = delete;
36     Brain& operator=(const Brain&) = delete;
37     Brain& operator=(Brain&&) = delete;
38     Unit& operator[](const Point& p)
39     {
40         return data[point_to_int(p)];
41     }
42     template <typename F>
43     void for_each(F _functor)
44     {
45         Point p;
46         for (p.x = 0; p.x != size.x; ++p.x)
47             for (p.y = 0; p.y != size.y; ++p.y)
48                 for (p.z = 0; p.z != size.z; ++p.z)
49                     _functor(p, operator[](p));
50     }
51     Point size;
52 private:
53     Unit* data;
54     int point_to_int(const Point& p)
55     {
56         return (p.x * size.y + p.y) * size.z + p.z;
57     }
58 };
59
60 void push_if_valid(std::queue<Point>& queue, Brain& brain, const Point& point)
61 {
62     if (point.x >= 0 && point.x < brain.size.x &&
63         point.y >= 0 && point.y < brain.size.y &&
64         point.z >= 0 && point.z < brain.size.z &&
66         !brain[point].collected)
67         queue.emplace(point);
68 }
69
70 void push_if_valid(std::queue<Point>& queue, Brain& brain, int x, int y, int z)
71 {
72     if (x >= 0 && x < brain.size.x &&
73         y >= 0 && y < brain.size.y &&
74         z >= 0 && z < brain.size.z)
75     {
76         Point p(x, y, z);
77         auto& unit = brain[p];
79             queue.emplace(std::move(p));
80     }
81
82 }
83
84 int main()
85 {
86     int size_x, size_y, size_z, threshold;
87     std::cin >> size_y >> size_z >> size_x >> threshold;
88     Point size(size_x, size_y, size_z);
89     Brain brain(size);
90     brain.for_each([](const Point& p, Unit& u) {
92         int t;
93         std::scanf("%d", &t);
95     });
96     int total = 0;
97     brain.for_each([=, &brain, &total](const Point& p, Unit& u) {
99             return;
100         int size = 0;
101         std::queue<Point> queue;
102         queue.push(p);
103         while (!queue.empty())
104         {
105             auto p = queue.front();
106             queue.pop();
107             auto& unit = brain[p];
109                 continue;
110             unit.collected = true;
111             ++size;
112             push_if_valid(queue, brain, p.x - 1, p.y, p.z);
113             push_if_valid(queue, brain, p.x + 1, p.y, p.z);
114             push_if_valid(queue, brain, p.x, p.y - 1, p.z);
115             push_if_valid(queue, brain, p.x, p.y + 1, p.z);
116             push_if_valid(queue, brain, p.x, p.y, p.z - 1);
117             push_if_valid(queue, brain, p.x, p.y, p.z + 1);
118         }
119         if (size >= threshold)
120             total += size;
121     });
122     std::cout << total;
123 }

posted on 2019-09-04 01:05  jerry_fuyi  阅读(478)  评论(0编辑  收藏  举报