ソリューション[SDOI2006]警備員
タイトル効果:指定された\(n-は\)木の点は、各点が全ての点をカバーするために必要最小限の設定点、それに接続されたすべてのポイントをカバーすることができます。
我々は、([D [U] fを\ ] \) で表される\(U \) 、ツリーのサブツリーのルートである\(U \)状態点をカバーである(D \)\で過ごした極小点を(\ (D = 0 \)場合\(U \)点は、親ノード、によって覆われている\(D = 1 \)の場合\(U \)ポイントは、独自で覆われている\(D = 2 \)場合\(U \)ポイントキルトノードカバレッジ)
それから
\ [分[U] [0] = \ sum_ {息子におけるV \(U)} F(F [v] [1]、F [v] [2])\]
\(分[U] [1] = \ sum_ {息子におけるV \(U)} F(F [v] [0]、F [v] [1]、[V] [2])+ヴァル(Fバツ)\)
\(fは[U]は[2] F F [X] [1] + \ sum_ {息子におけるV \(U)、V \ NEQ X}分(= [V] [1]、[V] [2 F ])\)
キーは、\([U] [2 F ] \) プロセスの\(N-2 ^ \)列挙時間爆発
我々は、前処理されてもよい\((合計= \和分 F [v] [1]、F [v] [2])\)
次に\(F [U] [2 ] =分\ {和-分(F [v] [1]、F [v] [2])+ F [v] [1] \} \)
コード:
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 2048;
vector<int> G[maxn];
template <typename T>
inline T min(const T &a,const T &b,const T &c){
return min(a,min(b,c));
}
inline void addedge(int from,int to){
G[from].push_back(to);
}
int f[maxn][3],val[maxn];
void dfs(int u,int faz){
int sum = 0;
f[u][1] = val[u];
f[u][2] = 0x7fffffff;
for(int v : G[u])
if(v != faz){
dfs(v,u);
f[u][0] += min(f[v][1],f[v][2]);
f[u][1] += min(f[v][0],f[v][1],f[v][2]);
sum += min(f[v][1],f[v][2]);
}
for(int v : G[u]){
if(v == faz)continue;
f[u][2] = min(f[u][2],sum - min(f[v][1],f[v][2]) + f[v][1]);
}
}
int n,u,m,v;
int main(){
scanf("%d",&n);
for(int i = 1;i <= n;i++){
scanf("%d",&u),scanf("%d %d",val + u,&m);
while(m--)scanf("%d",&v),addedge(u,v),addedge(v,u);
}
return dfs(1,0),printf("%d\n",min(f[1][1],f[1][2])),0;
}