ゲーム
実績 | 10 | オンタイム | 2020年3月10日(火)7時55分 |
割引 | 0.8 | ディスカウント時間 | 2020年4月7日火曜日午前23時55分 |
後半許可 | ノー | 閉会時間 | 2020年4月7日火曜日午前23時55分 |
誰かがコンピュータゲーム、特に戦略的なゲームをプレイするのが好き、私はしばしば非常に落ち込んで感じるように、時には彼ができるだけ早く解決策を見つけることができません。さて、次の質問に直面した:彼は城の道路は無向木を形成し、要塞中世の城でなければなりません。彼らはすべての側面を見ることができるように、接合部での兵士の最小値をスケジュールします。あなたは彼を助けることはできますか?
あなたの仕事は、兵士の最小数を与えています。
入力データの複数のセットを含みます。データの各セットは、データの各セットに、ツリーを表します。
最初の行は、ノードの数です。
ノードの次の数行は、以下の形式で記述されています。
ノード識別子:(道路数)ノード識別子番号2のノード識別子のノード識別子......道
若しくは
ノード識別子:(0)
N(0 <N <= 1500)ノードの場合、0からnまでの数であり、識別子ノード - 1は、整数です。各エッジは、テストケースで一度だけ表示されます。
各データセットについて、各兵士の整数所定の最小数で表されます。
テスト入力 | 予想される出力 | タイムリミット | メモリ制限 | 追加のプロセス | |
---|---|---|---|---|---|
テストケース1 |
|
|
1秒 | 64M | 0 |
これは、彼らがすべての側面を見ることができるように、木問題、必要な兵士の上部に複数のノードを提供します。
図1に示すように、処理の入力 - 図が記憶
接続された無向非環式グラフであるツリーのタイトル。考えてみましょ 隣接リストを 格納します。(ベクトル容器は、リストの操作を簡略化するために使用されます)
それぞれの側は一度だけ入力されます:トピックがあることを示しました。b点の後に入力された場合には、あなたが入力したAB側のために、その後のポイントは、B、Aの後に入力することはありません。このマップのタイトルを入力し、構造グラフを扱う必要があるとき、私たち一般のグラフトラバーサルの便宜のために、あなたが全体をしたい2点間のアップエッジ、無向グラフである:我々はできる、辺ABのために、ですアクセスAにB、bが通ってアクセスすることができます。
2、最適なダイナミックな展開見つける - ディープ検索
各側面を見ることが必要であることを確実にするために、その後、各辺の両端は、兵士の少なくとも一方の端部を有していなければなりません。各ポイントは2つのオプションがあります、ホールド兵士兵士を置きます。ツリーの構造と特性:ルートの下のサブノードがルートノードと各バイトの数をノードとその子孫は、サブツリーとして見ることができます。私たちは、深い検索使用できるように:検索ルートルートを、サブツリーのルートのそれぞれの検索を継続続きます。(第一ルートは選択することができます)
最小数を記録するために二次元配列DP [0..N-1、0..1]を使用して:
- ときに必要なツリーのルートのルートにルートノードホールド兵士の最小数:DP [ルート] [0]
- 兵士の最小数は、ルートノードを置く場合、ルートは必要なツリーのルートである:DP [ルート] [1]
この質問は、ボトムアップのソリューションでなければなりません。
最初の(次のノードを設定する)サブツリー DP [次] [0]、 [1] DP [次に] サブツリーのいずれかに基づいて算出されるように、計算される(そのノードのルートを設定)ツリー DP [ルート] [0]、 DP [ルート] [1]。最終的な答えはDPであるべきである[ルート] [0]、 DP [ルート] 小さな値[1]。
状態方程式の構築:
だから、どのようにそれの全体の木に果物の木から移行するには?二つの方法で:
- ルートノードホールド兵士場合:それぞれの子の兵士は次のノードを配置しなければならないことを、あなたはDP選択する必要があり、[次へ]を[1]
- ルートノード放電兵士場合:その子ノードの各々は、次の兵士の兵士が保持することができる配置することができるDP選択されるべきである[次] [0]、ルート自体と共にDP [次]小さな値[1] A
次のようにそのため、状態遷移方程式は、次のとおり
ACコンプリートコード:
//
// Created by LittleCat on 2020/3/10.
//
#include <cstdio>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;
#define MAX 1550
vector<int> point[MAX]; //map[i]储存节点i的临接节点集
bool vis[MAX]; //vis[i]表示节点i是否被访问过
int dp[MAX][2];
void DFS(int root) {
vis[root] = true; //标记已访问节点
/* 依次遍历根节点的每一个子节点 */
for (int i = 0; i < point[root].size(); i++) {
int next = point[root][i]; //子节点
if (vis[next]) //是已访问的前驱节点
continue; //避免往回搜索
DFS(next); //搜索子节点
dp[root][0] += dp[next][1];
dp[root][1] += min(dp[next][0], dp[next][1]);
}
dp[root][1]++;
}
int main() {
int n;
while (EOF != scanf("%d", &n)) {
/* 初始化数组 */
for (auto & i : point)
i.clear();
memset(vis, false, sizeof(vis));
memset(dp, 0, sizeof(dp));
/* 处理输入 */
for (int i, k; n; n--) {
scanf("%d:(%d)", &i, &k); //前驱节点i,边数k
for (int j; k; k--) {
scanf("%d", &j); //后继节点j
point[i].push_back(j);
point[j].push_back(i);
}
}
int root = 0;
DFS(root);
printf("%d\n", min(dp[root][0], dp[root][1]));
}
}
あなたが賞賛の役に立つ少しこの記事を希望する場合はご質問は、交換を確認してください持っている、姫姫〜
「手羽先をプログラミング」パブリックには個人的な歓迎の注目は、ここに深刻な行儀のコード農業の1ではありません。
----は、最も行儀ブログERを行い、ほとんどの固体プログラマが行います----
慎重に、通常のノートに集約各記事を、書くことを目指し、更新をプッシュします -