結果
| 問題 |
No.1069 電柱 / Pole (Hard)
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2022-01-28 16:47:29 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 308 ms / 2,000 ms |
| コード長 | 12,247 bytes |
| コンパイル時間 | 2,495 ms |
| コンパイル使用メモリ | 166,984 KB |
| 最終ジャッジ日時 | 2025-01-27 15:53:23 |
|
ジャッジサーバーID (参考情報) |
judge4 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 4 |
| other | AC * 79 |
ソースコード
#include <iostream>
#include <array>
#include <vector>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <algorithm>
#include <cmath>
#include <string>
#include <climits>
#include <cassert>
#include <iomanip>
#include <bitset>
#include <queue>
#include <deque>
#include <stack>
#include <functional>
#include <fstream>
#include <random>
#include <functional>
#define LEN(x) (long long)(x.size())
#define FOR(i, a, n) for(int i=(a);i<(n); ++i)
#define FOE(i, a) for(auto i : a)
#define ALL(c) (c).begin(), (c).end()
#define RALL(c) (c).rbegin(), (c).rend()
#define SUM(x) std::accumulate(ALL(x), 0LL)
#define MIN(v) *std::min_element(v.begin(), v.end())
#define MAX(v) *std::max_element(v.begin(), v.end())
#define EXIST(v, x) (std::find(v.begin(), v.end(), x) != v.end())
#define BIT_COUNT32(bit) (__builtin_popcount(bit))
#define BIT_COUNT64(bit) (__builtin_popcountll(bit))
typedef long long LL;
template<typename T> std::vector<T> make_v(size_t a){return std::vector<T>(a);}
template<typename T,typename... Ts> auto make_v(size_t a, Ts... ts){ return std::vector<decltype(make_v<T>(ts...))>(a,make_v<T>(ts...));} // C++14
template<typename T,typename V> typename std::enable_if<std::is_class<T>::value==0>::type fill_v(T &t,const V &v){t=v;}
template<typename T,typename V> typename std::enable_if<std::is_class<T>::value!=0>::type fill_v(T &t,const V &v){for(auto &e:t) fill_v(e,v);}
template<class T> inline T ceil(T a, T b) { return (a + b - 1) / b; }
void print() { std::cout << std::endl; }
template <class Head, class... Tail> void print(Head&& head, Tail&&... tail) { std::cout << head; if (sizeof...(tail) != 0) {std::cout << " ";} print(std::forward<Tail>(tail)...); }
template <class T> void print(std::vector<T> &v) {for (auto& a : v) { std::cout << a; if (&a != &v.back()) {std::cout << " ";} }std::cout << std::endl;}
template <class T> void print(std::vector<std::vector<T>> &vv) { for (auto& v : vv) { print(v); }}
void debug() { std::cerr << std::endl; }
template <class Head, class... Tail> void debug(Head&& head, Tail&&... tail) { std::cerr << head; if (sizeof...(tail) != 0) {std::cerr << " ";} print(std::forward<Tail>(tail)...); }
template <class T> void debug(std::vector<T> &v) {for (auto& a : v) { std::cerr << a; if (&a != &v.back()) {std::cerr << " ";} }std::cerr << std::endl;}
template <class T> void debug(std::vector<std::vector<T>> &vv) { for (auto& v : vv) { print(v); }}
inline bool inside(long long y, long long x, long long H, long long W) {return 0 <= y and y < H and 0 <= x and x < W; }
template<class T> inline double euclidean_distance(T y1, T x1, T y2, T x2) { return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); }
template<class T> inline T manhattan_distance(T y1, T x1, T y2, T x2) { return abs(x1 - x2) + abs(y1 - y2); }
template<typename T> T &chmin(T &a, const T &b) { return a = std::min(a, b); }
template<typename T> T &chmax(T &a, const T &b) { return a = std::max(a, b); }
bool is_bit_on(const unsigned long long bit, const unsigned int i) { return (bit >> i) & 1u; }
unsigned long long bit_set(const unsigned long long bit, const unsigned int i, const unsigned int b) {
assert(b == 0 or b == 1);
if (b == 0) { return bit & ~(1ull << i); }
else {return bit | (1ull << i); }
}
template<class T> inline std::vector<T> unique(std::vector<T> v) {
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
return v;
}
// 初項s交差d長さnの数列の和
long long sum_of_arithmetic_progression(long long s, long long d, long long n) {
return n * (2 * s + (n - 1) * d) / 2;
}
// xが2の階乗かどうか判定
bool is_power_of_two(long long x) {
return !(x & (x - 1));
}
long long gcd(long long a, long long b) {
if (b == 0) { return a; }
return gcd(b, a % b);
}
long long gcd(std::vector<long long> &v) {
long long ans = v[0];
for (int i = 1; i < (int) v.size(); ++i) {
ans = gcd(ans, v[i]);
}
return ans;
}
long long lcm(long long a, long long b) {
long long g = gcd(a, b);
return a / g * b;
}
const int INF = 1u << 30u; // 1,073,741,824
const long long LINF = 1ull << 60u;
const double EPS = 1e-9;
const long double PI = acos(-1.0);
const std::vector<int> dy2 = {0, 1}, dx2 = {1, 0}; // 右,下
const std::vector<int> dy4 = {0, 1, 0, -1}, dx4 = {1, 0, -1, 0};
const std::vector<int> dy6 = {0, -1, 0, 1, 1, 1}, dx6 = {1, 0, -1, 0, 1, -1};
const std::vector<int> dy8 = {0, -1, 0, 1, 1, -1, -1, 1}, dx8 = {1, 0, -1, 0, 1, 1, -1, -1};
template<typename T> class Edge {
public:
const int u;
const int v;
const T distance;
const int no;
Edge(int u, int v, T distance, int no=-1) : u(u), v(v), distance(distance), no(no) {
}
};
// Yen's algorithm
// 最短経路をK個見つける
// O(KN * SP).SPは最短経路問題の計算量
template<typename T> class KShortestPath {
public:
const int num_nodes;
const int K;
private:
std::vector<std::vector<int>> graph;
std::vector<Edge<T>> edges;
std::vector<T> distance;
std::vector<std::vector<int>> A; // A[k][i] = k 番目の最短経路の i 番目の edge
std::set<std::pair<T, std::vector<int>>> B; // deviation path
std::vector<int> removed_edge; // removed_edge[i] = edge i が使えない time
public:
KShortestPath(const int num_nodes, const int K) : num_nodes(num_nodes), K(K) {
this->graph.resize(num_nodes);
}
void add_directed_edge(const int u, const int v, const T w) {
const int no = this->edges.size();
this->graph[u].emplace_back(no);
this->edges.emplace_back(Edge(u, v, w, no));
}
void add_undirected_edge(const int u, const int v, const T w) {
const int no = this->edges.size();
this->graph[u].emplace_back(no);
this->graph[v].emplace_back(no + 1);
this->edges.emplace_back(Edge(u, v, w, no));
this->edges.emplace_back(Edge(v, u, w, no));
}
Edge<T> get_edge(const int edge_no) const {
return this->edges[edge_no];
}
// k番目の最短経路の距離を返す
// 0-index
T k_shortest_path_distance(const int k) const {
return this->distance.at(k);
}
// k番目の最短経路の辺のindexを格納した配列を返す
// 0-index
std::vector<int> k_shortest_path(const int k) const {
return this->A.at(k);
}
size_t num_shortest_path() const {
return A.size();
}
void build(const int s, const int t) {
assert(s < this->num_nodes);
assert(t < this->num_nodes);
assert(s != t);
this->removed_edge.resize(this->edges.size(), -1);
int time = 0;
// 1つ目の最短経路を見つける
{
auto[dist, path] = this->dijkstra(s, t, 0, std::unordered_set<int>());
if (path.empty()) {
return;
}
this->A.emplace_back(path);
this->distance.emplace_back(dist);
}
for (int _ = 1; _ < this->K; ++_) {
const auto &last_path = this->A.back();
std::vector<int> spur_root;
T now_distance = 0;
std::vector<int> candidate(A.size());
std::iota(candidate.begin(), candidate.end(), 0);
std::unordered_set<int> used_node;
for (int i = 0; i < int(last_path.size()); ++i) {
const int edge_idx = last_path[i];
const auto &edge = this->edges[edge_idx];
const int spur_node = edge.u;
used_node.insert(spur_node);
std::vector<int> accept;
// 使えない辺を見つける
for (const auto c : candidate) {
const auto &path_k = this->A[c];
if (int(path_k.size()) < i) {
continue;
}
this->removed_edge[this->edges[path_k[i]].no] = time;
// 次回にも使える最短経路
if (path_k[i] == last_path[i]) {
accept.emplace_back(c);
}
}
candidate = move(accept);
auto [dist, suf_path] = this->dijkstra(spur_node, t, time, used_node);
time++;
// spur_node -> t へのパスがみつからなかった
if (suf_path.empty()) {
spur_root.push_back(edge_idx);
now_distance += edge.distance;
continue;
}
// 候補の経路を作成
std::vector<int> path = spur_root;
path.insert(path.end(), suf_path.begin(), suf_path.end());
this->B.insert({now_distance + dist, path});
spur_root.push_back(edge_idx);
now_distance += edge.distance;
}
// これ以上最短経路はない
if (B.empty()) {
break;
}
// 候補のうち最短の経路を確定にする
this->A.emplace_back(this->B.begin()->second);
this->distance.emplace_back(B.begin()->first);
B.erase(B.begin());
}
}
private:
// 負辺がないとき用
std::pair<T, std::vector<int>> dijkstra(const int start, const int end, const int time, const std::unordered_set<int> &used_node) const {
//[(最短距離, node番号)]のque(距離が近い順にとりだす)
std::priority_queue<std::pair<T, int>, std::vector<std::pair<T, int>>, std::greater<std::pair<T, int>>> que;
que.push({0, start});
std::vector<std::pair<int, int>> prev(this->num_nodes); // 経路復元用
std::vector<T> distance(this->num_nodes, std::numeric_limits<T>::max()); // startからの距離
distance[start] = 0;
std::vector<bool> used(this->num_nodes);
while (not que.empty()) {
const auto [now_dist, u] = que.top();
que.pop();
if (used[u]) {
continue;
}
used[u] = true;
if (u == end) {
break;
}
for (const auto edge_idx : this->graph[u]) {
const auto &edge = this->edges[edge_idx];
if (this->removed_edge[edge.no] == time) {
continue;
}
const auto v = edge.v;
const auto new_dist = now_dist + edge.distance;
if (used_node.find(v) != used_node.end()) {
continue;
}
if (new_dist < distance[v]) {
prev[v] = {u, edge_idx};
distance[v] = new_dist;
que.push({new_dist, v});
}
}
}
// t にたどり着けなかった
if (not used[end]) {
return {0, {}};
}
std::vector<int> path;
int now = end;
while (now != start) {
path.emplace_back(prev[now].second);
now = prev[now].first;
}
reverse(path.begin(), path.end());
return {distance[end], path};
}
};
using namespace std;
int main() {
cin.tie(0);
ios::sync_with_stdio(0);
int N, M, K, X, Y;
cin >> N >> M >> K;
cin >> X >> Y;
X--; Y--;
vector<int> P(N), Q(N);
for (int i = 0; i < N; ++i) {
cin >> P[i] >> Q[i];
}
KShortestPath<long double> ksp(N, K);
for (int i = 0; i < M; ++i) {
int a, b;
cin >> a >> b;
a--; b--;
auto d = sqrt((P[a] - P[b]) * (P[a] - P[b]) + (Q[a] - Q[b]) * (Q[a] - Q[b]));
ksp.add_undirected_edge(a, b, d);
}
ksp.build(X, Y);
for (int i = 0; i < K; ++i) {
if (i < int(ksp.num_shortest_path())) {
print(ksp.k_shortest_path_distance(i));
// FOE(r, ksp.k_shortest_path(i)) {
// cout << ksp.get_edge(r).u << "->" << ksp.get_edge(r).v << ", ";
// }
// cout << endl;
}
else {
print(-1);
}
}
return 0;
}