一本通1579【例 5】皇宫看守
1579: 【例 5】皇宫看守
时间限制: 1000 ms 内存限制: 524288 KB
题目描述
太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫。
皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状,某些宫殿间可以互相望见。大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。
可是陆小凤手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫。
帮助陆小凤布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少。
输入格式
输入中数据描述一棵树,描述如下:
第一行 n,表示树中结点的数目。
第二行至第 n+1 行,每行描述每个宫殿结点信息,依次为:该宫殿结点标号 i (0<i≤n),在该宫殿安置侍卫所需的经费 k,该边的儿子数 m,接下来 m 个数,分别是这个节点的 m 个儿子的标号r1,r2,⋯,rm。
对于一个 n 个结点的树,结点标号在 1 到 n 之间,且标号不重复。
输出格式
输出最少的经费
样例
样例输入
6
1 30 3 2 3 4
2 16 2 5 6
3 5 0
4 4 0
5 11 0
6 5 0
样例输出
25
样例解释
有六个区域被安排的情况如左图所示。
如右图,灰色点安排了警卫,2 号警卫可以观察 1,2,5,6,33 号警卫可以观察 1,3,4 号警卫可以观察 1,4。
总费用:16+5+4=25
数据范围与提示
对于 100% 的数据,0<n≤1500。
sol:这道题我开始看成了没有上司的舞会,GG了无数发后发现它观察的是点(那道题是边)
dp[x][0,1][0,1]表示那个点是否有哨兵,是否安全,然后暴力转移就ojbk了(其实dp[1][0]是不存在的,其实就三个)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; inline int read() { int s=0; bool f=0; char ch=' '; while(!isdigit(ch)) { f|=(ch=='-'); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(long long x) { if(x<0) { putchar('-'); x=-x; } if(x<10) { putchar(x+'0'); return; } write(x/10); putchar((x%10)+'0'); return; } inline void writeln(int x) { write(x); putchar('\n'); return; } #define W(x) write(x),putchar(' ') #define Wl(x) writeln(x) const int N=1505,M=3005,inf=0x3f3f3f3f; int n,Cost[N]; struct Tree { int tot,Next[M],to[M],head[N]; inline void add(int x,int y) { Next[++tot]=head[x]; to[tot]=y; head[x]=tot; return; } long long dp[N][2][2]; //第一维[0,1]表示这个点是否有士兵 //第二维[0,1]表示这个点是否安全 inline void dfs(int x,int fa) { int i; long long Min=inf; bool bo=0; for(i=head[x];i;i=Next[i]) if(to[i]!=fa) { dfs(to[i],x); dp[x][0][0]+=dp[to[i]][0][1]; if(dp[to[i]][0][1]>dp[to[i]][1][1]) bo=1; else Min=min(Min,dp[to[i]][1][1]-dp[to[i]][0][1]); dp[x][0][1]+=min(dp[to[i]][0][1],dp[to[i]][1][1]); dp[x][1][1]+=min(min(dp[to[i]][0][0],dp[to[i]][0][1]),dp[to[i]][1][1]); } if(!bo)dp[x][0][1]+=Min; dp[x][1][1]+=Cost[x]; return; } inline void Solve() { dfs(1,0); Wl(min(dp[1][0][1],dp[1][1][1])); return; } inline void Init() { tot=0; memset(head,0,sizeof head); return; } }T; int main() { // freopen("guard6.in","r",stdin); // freopen("my.out","w",stdout); int i; R(n); T.Init(); for(i=1;i<=n;i++) { int rt,k,x; R(rt); R(Cost[rt]); R(k); while(k--) {R(x); T.add(rt,x); T.add(x,rt);} } T.Solve(); return 0; } /* input 6 1 30 3 2 3 4 2 16 2 5 6 3 5 0 4 4 0 5 11 0 6 5 0 output 25 input 1 1 2 0 output 2 input 9 2 16 3 1 3 4 1 8000 3 5 6 7 3 6000 1 8 4 8000 0 5 1 1 9 6 900 0 7 100 0 8 2 0 9 20 0 output 1019 */
河田は河田、赤木は赤木……。
私は誰ですか。教えてください、私は誰ですか。
そうだ、俺はあきらめない男、三井寿だ!