AtCoder Beginner Contest 226 C - Martial artist
問題の要約
武術家の覚えられる技がN個あり,技1,2,...,Nと名前がついている。
1<=i<=Nについて,技iを習得するには時間Tiの修練が必要で,さらに,修練の開始時点で技Ai,1,Ai,2,...,Ai,Kiをすでに習得している必要がある。
ここで,1<=j<=Kiについて,Ai,j<iであることが保証されている。
時刻0の時点で技を一つも覚えていない。同時に一つの技に対する修練しかできず,また,一度始めた修練を途中でやめることもできない。
技Nを習得するのに必要な時間の最小値を求めよ。
制約
1<=N<=2*10^5
1<=Ti<=10^9
0<=Ki<i
1<=Ai,j<i
入力
N
T1 K1 A1,1 A1,2 ... A1,K1
T2 K2 A2,1 A2,2 ... A2,K2
.
.
.
TN KN AN,1 AN,2 ... AN,KN
考え方
1,技の名前を1つずらす
1<=i<=N => 0 <=i<=N-1
2,技iを習得するには,修練の開始時点で技Ai,1,...,Ai,Kiを習得している必要があることから,技Ai,1,...,Ai,Kiから技iへの有向辺がある有向グラフDGを作ることができる。
3,この有向グラフDGでは技N-1を習得する時間を計算するのは難しい。
例えば,技N-1へ繋がる一番最初の技を全て知っておく必要がある。
また,技N-1へ繋がらない技の修練時間を計算しないようにしないといけない。
4,上の問題を解決するため,技N-1にだけ繋がっている技だけをグラフとして探索したい。
5,そのようにするには,有向グラフDGの辺の向きを逆にした有向グラフDGRを考える。
6,そうすると,技N-1から探索して.訪れた技の習得時間を足してゆけばよい。
そして,技N-1へ繋がらない技には訪れることはない。
実際のプログラム
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<vector<long long>> DGR;
vector<long long> T;
vector<bool> visited;
long long alltime;
void dfs(long long v){
alltime += T[v];
visited[v] = true;
for(long long i = 0; i < DGR[v].size(); i++){
long long w = DGR[v][i];
if(visited[w] == false){
dfs(w);
}
}
return;
}
int main(){
long long N;
cin >> N;
DGR.resize(N);
T.resize(N, 0);
for(long long i = 0; i < N; i++){
cin >> T[i];
long long Ki;
cin >> Ki;
for(long long j = 0; j < Ki; j++){
long long Aj;
cin >> Aj;
DGR[i].push_back(Aj-1);
}
}
alltime = 0;
visited.resize(N, false);
dfs(N-1);
cout << alltime << endl;
return 0;
}