タイトル
私たちは、「バイナリシーケンスS」と呼んで0,1,2からなる文字列に次のルールに従ってバイナリツリーを表すことができます:
例えば、バイナリツリーは、図バイナリシーケンスによって表すことができるS=21200110
表されます。
あなたの仕事は、バイナリツリーのノードを染色することです。各ノードは、赤色、緑色または青色に着色することができます。さらに、ノードとその子ノードの色は、ノードが2つのつの子ノードを有する場合、2つのつの子ノードの色が異なっていなければならない、異なっていなければなりません。与えられた二分木、緑色に着色される大部分の点の最小数ツリー要求のバイナリシーケンス
入力形式
せいぜい入力ファイルの唯一の行ない、(5 \回10 ^ 5 \ \) 文字がバイナリシーケンスを表します
出力フォーマット
出力ファイルは、1行の点の最もおよび最小数は緑色染色することができ、それぞれのために、2つの数値を含んでいます
サンプル入力
1122002010
サンプル出力
5 2
問題の解決策
直接入力ツリーDPへのDFS。
定義maxv
およびminv
2つの配列maxv[i][j]
で表される\(I \)グリーン染色されたノードの数、の米国特許第サブツリーのルートノードまでの\(J = 0 \) 、根が緑色に染色され、もし\(J 1 = \) 、根が赤色に染色され、場合\(J = 2 \) 、ルートノードは青色に染色されました。
minv
同様に、緑色は、ノードの最小数を染色することができる表します。
ルートノードが子ノードは、ルートノードの子ノードとしない色を有する場合、そう残りの2色から最大のアップデートを選択します。ルートノートが緑色の場合、値は1(マルチルートを追加する必要があり、DP緑色ノードnode)
ルートノードは、2人の子供、及び二つのサブルートノードできない色、2つだけの色を有する場合、これに最大更新から選択された2つのケースでは、2つのケースがある。また、ノートときケースと、緑色のルート。
だから、どのようにDFS特別なシーケンスいますか?
木が空でない場合は、まず、必ず最初の項目は、ルートノード、いくつかのサブツリーのルートノードを有していてもよく、その後の最初の項目であること、そして左の子は、ツリーのルート第二項、注意でなければならないこと唯一のサブツリー場合、私は左のサブツリーとして見サブツリーを置きます。
特定のリーフノードが0であることを確認するようそして左のサブツリー同じ再帰的な操作が戻って、あなたがこの位置、最後の一つの配列内のサブツリーのツリーの位置に戻ることができたときに、国境をチェックする必要はありませんので、0バックに遭遇しましたプラスワンは、右のサブツリー(2つのサブツリーがある場合)です。
だから、それは成果なしDFSのことができるようになります
コード
#include <iostream>
#include <string>
using namespace std;
const int maxn = 10005;
string s;
int maxv[maxn][3], minv[maxn][3];
int dfs(int root) {
if (s[root] == '0') {
maxv[root][0] = minv[root][0] = 1; // 因为叶节点没有子树,所以若该叶节点不为绿色,这棵子树中绿色节点的个数为0,反之为1
return root; // 这棵子树的结尾坐标
}
int lend = dfs(root + 1); // 递归左子树
if (s[root] == '1') {
maxv[root][0] = max(maxv[root+1][1],maxv[root+1][2])+1; // 这个是绿色的,需要额外算上根节点
maxv[root][1] = max(maxv[root+1][0],maxv[root+1][2]); // 这两种代表什么颜色其实无关紧要
maxv[root][2] = max(maxv[root+1][0],maxv[root+1][1]);
minv[root][0] = min(minv[root+1][1],minv[root+1][2])+1;
minv[root][1] = min(minv[root+1][0],minv[root+1][2]);
minv[root][2] = min(minv[root+1][0],minv[root+1][1]);
return lend; // 如果有一棵子树,左子树的结尾就是这棵子树的结尾
} else {
int rend = dfs(lend + 1); // 根据左子树的结尾递归右子树
maxv[root][0] = max(maxv[root+1][1]+maxv[lend+1][2],maxv[root+1][2]+maxv[lend+1][1])+1;
maxv[root][1] = max(maxv[root+1][0]+maxv[lend+1][2],maxv[root+1][2]+maxv[lend+1][0]);
maxv[root][2] = max(maxv[root+1][0]+maxv[lend+1][1],maxv[root+1][1]+maxv[lend+1][0]);
minv[root][0] = min(minv[root+1][1]+minv[lend+1][2],minv[root+1][2]+minv[lend+1][1])+1;
minv[root][1] = min(minv[root+1][0]+minv[lend+1][2],minv[root+1][2]+minv[lend+1][0]);
minv[root][2] = min(minv[root+1][0]+minv[lend+1][1],minv[root+1][1]+minv[lend+1][0]);
return rend; // 如果有两棵子树,右子树的结尾才是这棵子树的结尾
}
}
int main() {
cin >> s;
dfs(0);
// 三种情况选最大/最小
cout<<max(maxv[0][0], max(maxv[0][1], maxv[0][2]))<<" "<<min(minv[0][0], min(minv[0][1], minv[0][2]))<<endl;
return 0;
}
PS
2つのサイトで、この質問には多少異なる最近記憶力低下は、第2の上部、クレイジーREに提出私の最初の書き込みを、輝く理由を見つけることができませんでした半分の時間をサイディング、データの範囲...