備忘録

まとめておきたいことのメモ 主にプロコンのこと

天下一プログラマーコンテスト2016A B問題

この問題を解きました。

tenka1-2016-quala.contest.atcoder.jp

問題設定がややこい感じもしますが、解法を思いつくのはそんなに難しくない気がします、ただ実装が大変だった。

答えはこちら

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <cstring> 
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <map>
    #include <queue>
    #include <utility>
    #include <vector>
    #include <set>
    #include <memory.h>
    #include <iomanip>
    #include <bitset>
    #include <list>
    #include <stack>
     
    using namespace std;
     
    #define pai 3.14159265359
    #define mod 1000000007
     
    bool ischecked[1001];
    vector<vector<int> > childleaf(1001), children(1001);
    int c[1001];
     
    vector<int> getchildleaf(int n)
    {
        if(ischecked[n]) return childleaf[n];
        ischecked[n] = true;
        vector<int> result;
        if(children[n].size() == 0){
            result.push_back(n);
        } else {
            for(int i = 0; i < children[n].size(); i++){
                vector<int> tmp = getchildleaf(children[n][i]);
                result.insert(result.end(), tmp.begin(), tmp.end());
            }
        }
        childleaf[n] = result;
        return childleaf[n];
    }
     
    int getminc(int n)
    {
        if(children[n].size() == 0) return c[n];
        int result = 100001;
        for(int i = 0; i < children[n].size(); i++){
            result = min(result, getminc(children[n][i]));
        }
        return result;
    }
     
    int solve(int n)
    {
        long long int nowans = 0;
        for(int i = 0; i < children[n].size(); i++){
            int nowchild = children[n][i];
            int nowc = c[nowchild];
            if(nowc != -1){
                nowans += nowc;
            } else {
                nowc = getminc(nowchild);
                // cout << nowchild << " " << nowc << endl;
                nowans += nowc;
                for(int j = 0; j < childleaf[nowchild].size(); j++){
                    c[childleaf[nowchild][j]] -= nowc;
                }
                nowans += solve(nowchild);
            }
     
        }
        return nowans;
    }
     
    int main()
    {
        int n, m;
        cin >> n >> m;
        ischecked[0] = false;
        for(int i = 1; i < n; i++){
            ischecked[i] = false;
            c[i] = -1;
            int p;
            cin >> p;
            children[p].push_back(i);
        }
        for(int i = 0; i < m; i++){
            int b, cinput;
            cin >> b >> cinput;
            c[b] = cinput;
        }
        getchildleaf(0);
        // for(int i = 0; i < n; i++){
        //     cout << i << ": ";
        //     for(int j = 0; j < childleaf[i].size(); j++){
        //         cout << childleaf[i][j] << " ";
        //     }
        //     cout << endl;
        // }
        cout << solve(0) << endl;
        return 0;
    }

0から順に、そのノードの子のそれぞれに対して、下につながっている葉のうちもっとも小さな値mincを選びます。それをそのノードと子の枝の重みにします。最後に下につながっている葉のCの値をminc分除いておきます。これを繰り返せば答えが出ます。
説明しづらい。

なんどもCを更新しているからTLEするかなと思いましたが、ノード数が少なかったからか大丈夫だったみたいです。