yokobuttonの不定期で競技プログラミングをするブログ

不定期で解けた競技プログラミングコンテストの問題を載せています。

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;
}