7-15星間遠征(25ポイント)
ある遠い将来、新しい人間は次のような星間遠征を実行できるようになります。宇宙にはいくつかのジャンプポイントがあり、人間の宇宙船は各ジャンプポイントで光速よりも速く他のジャンプポイントにジャンプできます。もちろん、一般的に言って、各ジャンプは一定量のエネルギーを消費しますが、未知の物質の影響により、特定のジャンプは代わりに一定量のエネルギーを得ることができます。
すべてのジャンプポイントの中で、人類の本来の故郷である地球が最も特別であり、これが「ジャンプの目的地ではない」唯一のジャンプポイントです。つまり、地球から他のポイントにジャンプすることができます。しかし、他のどの地点からでも、地球にジャンプすることはできません。
地球から出発して星間遠征を開始する宇宙船があり、移動コストを考慮して、目的地に到達するときのエネルギー消費の上限を設定すると、宇宙船がこのエネルギー消費制限の下で到達できるいくつかのジャンプポイントがあります、および一部のジャンプポイントに到達できません。次に、到達可能なすべてのジャンプポイントを見つけるようにプログラムしてください。
注意点:
- 到達可能なジャンプポイントとは、宇宙船がこのポイントに到着したときのエネルギー消費量が制限内であることを意味します。到達可能なすべてのポイントは、1回の旅行での宇宙船の移動ではなく、そのようなポイントの集合を参照します。通過ポイント。たとえば、宇宙船が地球から出発する場合、エネルギー制限がプロキシマケンタウリまたはシリウスの2つのポイントのいずれかにジャンプするのに十分であり、1回の旅行でこれらの2つのポイントに到達できない場合、「すべての到達可能なポイント」には次のものが含まれます。この2つのポイント、つまりジャンプ能力の観点から、これらの2つのポイントは「到達可能」です。
- 特定のジャンプは宇宙船のエネルギーを増加させる可能性があり、特定のポイントから開始し、数回ジャンプした後、このポイントに戻る可能性があります。しかし、エネルギーの法則によって次のことが決まります。このポイントに戻ると、宇宙船のエネルギーは、最初にこのポイントから開始したときよりも低くなる可能性があります(そうでない場合、「永久機関」が存在します)。
- エネルギー消費量の上限は、中間点のエネルギー状態に関係なく、目的地(特定のジャンプポイント)に到達するときに消費されるエネルギーを判断します。一部のジャンプではエネルギーが増加するため、この状況は完全に発生する可能性があることに注意してください。ポイントAにジャンプすると、エネルギー消費量が制限を超えますが、ポイントAからポイントBにジャンプするとエネルギーが増加し、ポイントBにジャンプするとエネルギーが増加します。 、総エネルギー消費量制限を超えないでください。この時点で、ポイントAは到達不能と見なされ、ポイントBは到達可能です。
入力フォーマット:
まず、正の整数N(N <= 2000)を続けて指定します。これは、宇宙のジャンプポイントの数です。
次のN行では、i番目の行(i = 1 ... N)は、iの番号が付けられたジャンプポイントの情報を次の形式で記述しています。
k p1 d1 p2d2…pkdk(スペースで区切る)
その中で、整数kはこのジャンプポイントから始まる他のポイントへのジャンプの数、次のkは非ゼロの整数pi di、piはジャンプできる特定のポイントの数、diはポイントpiにジャンプする宇宙船のエネルギー変化、diが正の場合、このジャンプはエネルギーを増加させる(diを増加させる)ことを意味し、diは負を意味し、このジャンプはエネルギーを消費することを意味します(消費の値は| di |) 。この質問は、地球から到達可能なジャンプポイントまでに消費された(または増加した)エネルギーの合計の絶対値が108を超えないことを保証します。
最後の行は正の整数Eを示します。これは、宇宙船が出発するときに設定されるエネルギー消費の上限を表します。
出力フォーマット:
宇宙船が到達できるすべてのジャンプポイントの番号を小さいものから大きいものの順に出力し、行ごとに1つの番号を出力します(行の終わりに改行を付けます)。
促す:
- ジャンプポイント「地球」は常に「到達可能」と見なされ、開始ポイントであるため、このポイントに到達するためにエネルギーを必要としません。
- 地球の数は必ずしも1ではありません。
入力サンプル:
これが入力のセットです。例えば:
6
3 2 -3 4 -5 3 -6
1 6 -6
2 4 -2 5 -2
2 3 -3 6 -3
1 4 4
0
7
サンプル出力:
対応する出力をここに示します。例えば:
1
2
3
4
6
問題解決
このトピックでは、最短パスとしてダイクストラアルゴリズムを使用していますが、各ノードに繰り返しアクセスする場合があります。vis[]タグ配列を削除するだけです。
コード
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <set>
using namespace std;
const int maxn = 2002;
bool vis[maxn];
bool F[maxn][maxn];
int G[maxn][maxn], dist[maxn];
set<int> ans;
struct node {
int id, va;
};
struct cmp {
bool operator()(const node& a, const node& b) {
return a.va > b.va; }
};
int getStart(int N) {
for (int i = 1; i <= N; i++)
if (!vis[i]) return i;
return 0;
}
void Dijkstra(int start, int N, int E) {
priority_queue<node, vector<node>, cmp> q;
memset(dist, 0x3f, sizeof(dist));
memset(vis, false, sizeof(vis));
dist[start] = 0;
q.push({
start, dist[start]});
while (!q.empty()) {
int v = q.top().id;
int va = q.top().va;
q.pop();
// if (vis[v]) continue;
vis[v] = true;
for (int i = 1; i <= N; i++) {
if (F[v][i]) {
// cout << v << " " << i << endl;
if (dist[v] + G[v][i] < dist[i]) {
dist[i] = dist[v] + G[v][i];
q.push({
i, dist[i]});
}
}
}
}
for (int i = 1; i <= N; i++) {
// cout << dist[i] << " ";
if (dist[i] <= E) ans.insert(i);
}
// cout << endl;
}
int main() {
int N, k, E;
cin >> N;
for (int i = 1; i <= N; i++) {
cin >> k;
int p, d;
for (int j = 1; j <= k; j++) {
cin >> p >> d;
vis[p] = true;
F[i][p] = true;
G[i][p] = -d;
}
}
cin >> E;
int start = getStart(N);
memset(vis, false, sizeof(vis));
Dijkstra(start, N, E);
for (auto i = ans.begin(); i != ans.end(); i++) {
cout << *i << endl;
}
system("pause");
return 0;
}