質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

1680閲覧

Atcoder Beginner Contest 137 E でのTLE,WAの原因は何でしょうか

fadshaue

総合スコア3

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/08/15 06:32

質問

AtcoderBeginnerContest137-Eにおいて、WAやTLEが生じる原因がわからない。
(動作チェック用の出力をコメントアウトしてあります。)

問題文

1 から N までの番号がつけられた N 頂点と M 辺からなる有向グラフがあります。
i 番目の辺は頂点 A_i から頂点 B_i へと向かい、この辺の上には C_i 枚のコインが置かれています。
また、頂点 N にはボタンが設置されています。

このグラフ上でゲームを行います。 あなたは頂点 1 でコインを 0 枚持ってゲームを開始し、辺をたどってコインを拾いながら頂点 N を目指します。
1本の辺を通るには 1 分の時間がかかり、辺を通るたびにその辺の上に置かれているすべてのコインを拾うことができます。
ゲームの世界ではよくあるように、ある辺を通ってその上のコインを拾っても、その辺を次に通る際には同じ枚数のコインが再び出現しており、それらを再び拾うことができます。

頂点 N に到着したとき、ボタンを押してゲームを終了することができます。(ボタンを押さずに移動を続けることもできます。)
ただし、ゲームを終了する際に、ゲーム開始からの経過時間を T 分として T×P 枚のコインの支払いが要求されます。
持っているコインの枚数が T×P 枚未満の場合は、代わりに持っているコインをすべて支払います。

この支払いの後に残ったコインの枚数があなたのスコアとなります。 獲得できるスコアの最大値が存在するか判定し、存在する場合はその最大値を求めてください。

方針

  • かかった時間に応じて最後に支払う -> 負の所持コインを許容し、辺を通るたびに支払う。
  • 1(スタート)からN(ゴール)にたどり着けなくなる辺は除去。
  • ベルマンフォード法を使用して最大を調べる。また、無限にコインを獲得するルートを検出。

結果

ほとんどはAC(正解)。一部WA(不正解)とTLEが生じる。

ソースコード

cpp

1#include <iostream> 2#include <vector> 3#include <queue> 4using namespace std; 5 6#define INF 100000 7 8int N, M, P; 9 10typedef struct edge 11{ 12 int from; 13 int to; 14 int cost; 15} edge; 16 17int main() 18{ 19 cin >> N >> M >> P; 20 int dist[N + 1];//頂点ごとのコストを格納 21 vector<edge> e1;//不要部分除去前の辺リスト 22 vector<edge> e2;//不要部分除去後の辺リスト 23 //コストの初期化 24 for (int i = 1; i <= N; i++) 25 { 26 if (i != 1) 27 dist[i] = INF; 28 else 29 dist[i] = 0; 30 } 31 //辺の登録 32 { 33 edge ed; 34 for (int i = 0; i < M; i++) 35 { 36 cin >> ed.from >> ed.to >> ed.cost; 37 ed.cost = P - ed.cost; 38 e1.push_back(ed); 39 } 40 } 41 //Nにたどり着けなくなる頂点、辺の除去 42 { 43 int fromOne[N + 1];//1からiにたどり着ける場合fromOne[i]=1 other 0 44 int toN[N + 1];//iからNにたどり着ける場合toN[i]=1 other 0 45 for (int i = 1; i <= N; i++) 46 { 47 fromOne[i] = 0; 48 toN[i] = 0; 49 } 50 queue<int> que; 51 que.push(1); 52 while (!que.empty()) 53 { 54 fromOne[que.front()] = 1; 55 for (auto &&i : e1) 56 { 57 //cout << que.front() << "から移動" << endl; 58 if (i.from == que.front() && fromOne[i.to] == 0) 59 { 60 //cout << i.from << "->" << i.to << "へ移動" << endl; 61 que.push(i.to); 62 } 63 } 64 que.pop(); 65 } 66 //cout << "-------" << endl; 67 que.push(N); 68 while (!que.empty()) 69 { 70 toN[que.front()] = 1; 71 for (auto &&i : e1) 72 { 73 //cout << que.front() << "から移動" << endl; 74 if (i.to == que.front() && toN[i.from] == 0) 75 { 76 //cout << i.to << "->" << i.from << "へ移動" << endl; 77 que.push(i.from); 78 } 79 } 80 que.pop(); 81 } 82 for (auto &&i : e1) 83 { 84 if (fromOne[i.from] * toN[i.to] == 1) 85 { 86 e2.push_back(i); 87 } 88 } 89 } 90 //コストの緩和 91 for (int i = 0; i < N; i++) 92 { 93 for (auto &&j : e2) 94 { 95 dist[j.to] = min(dist[j.to], dist[j.from] + j.cost); 96 } 97 } 98 //負経路の探索 99 for (auto &&i : e2) 100 { 101 if (dist[i.to] > dist[i.from] + i.cost) 102 { 103 cout << "-1" << endl; 104 return 0; 105 } 106 } 107 cout << max(-1 * dist[N], 0) << endl; 108 return 0; 109} 110

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

試していませんが、気になるのは

#define INF 100000

while (!que.empty()) { fromOne[que.front()] = 1; for (auto &&i : e1) { //cout << que.front() << "から移動" << endl; if (i.from == que.front() && fromOne[i.to] == 0) { //cout << i.from << "->" << i.to << "へ移動" << endl; que.push(i.to); } } que.pop(); }

です
INFについては、一つの辺のコストが±10^5程なので、INFはN * 10^5ほどは確保しておかないと正しい結果にならない可能性があります。おそらくWAはこれが原因です。

もう一つがスタートとゴールそれぞれについて到達可能か調べる部分ですが、単純計算で外側のwhileが N 回、内側のforが M 回ループするので、O(NM)かかります。さらにこの書き方だと同じ頂点が繰り返しQueueにプッシュされるので、さらに悪くなります。おそらくこれがTLEの原因でしょう。

投稿2019/08/27 03:55

yudedako67

総合スコア2047

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問