Vijos 1144 小胖守皇宫 [树形dp]

P1144小胖守皇宫

描述
huyichen世子事件后,xuzhenyi成了皇上特聘的御前一品侍卫。
皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状;某些宫殿间可以互相望见。大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。
可是xuzhenyi手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫。
帮助xuzhenyi布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少。

输入格式
输入文件中数据表示一棵树,描述如下:
第1行 n,表示树中结点的数目。
第2行至第n+1n+1行,每行描述每个宫殿结点信息,依次为:该宫殿结点标号 i ( 0 < i ≤ n0 < i ≤ n ),在该宫殿安置侍卫所需的经费k,该点的儿子数m,接下来m个数,分别是这个节点的m个儿子的标号r1,r2,⋯,rmr1,r2,⋯,rm。
对于一个 n(0 < n ≤ 15000 < n ≤ 1500)个结点的树,结点标号在1到n之间,且标号不重复。保证经费总和不超过231−1231−1。

输出格式
输出文件仅包含一个数,为所求的最少的经费。

样例输入
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


对于一个节点 u 有自己守、父亲守、儿子守 三种状态,那么如果对应用 0 1 2 表示
- dp[u][0] = ∑min(dp[v][0,1,2]) + cost[u]
- dp[u][1] = ∑min(dp[v][0,1]) 并且至少有一个取 0状态
- dp[u][2] = ∑dp[v][1]

对于dp[u][1]可以设 delta = min(dp[v][0] - dp[v][1]) , 那么如果delta > 0 说明没有一个儿子选了自己守,那么此时就要加上这个最小的差量

注意最后只去存在的状态,并且初值不存在的状态不应该太大, 否则累加时可能超出 INT

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
const int INF=0x3f3f3f3f;
const int maxn=1505;
struct Edge
{
    int to,next;
}edge[maxn];
int head[maxn];
int maxedge;
int in[maxn],cost[maxn];
int root,n;
inline int find_root()
{
    for(int i=1;i<=n;i++)
        if(!in[i]) return i;
    return -1; //default
}
inline void addedge(int u,int v)
{
    edge[++maxedge]=(Edge){ v,head[u] };
    head[u]=maxedge;
    in[v]++;
}
inline void init()
{
    memset(head,-1,sizeof(head));
    maxedge=-1;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int u,cnt;
        scanf("%d",&u);
        scanf("%d%d",cost+u,&cnt);
        for(int i=1;i<=cnt;i++)
        {
            int tmp;
            scanf("%d",&tmp);
            addedge(u,tmp);
        }
    }
    root = find_root();
}
int f[maxn][3];
void dfs(int u)
{
    if(!~head[u])
    {
        f[u][0] = cost[u];
        f[u][1] = INF / maxn; // if INF here, easy to exceed the maxlimit of integer!!!
        f[u][2] = 0;
        return;
    }
    int delta=INF;
    for(int i=head[u];~i;i=edge[i].next)   {
        int v=edge[i].to;
        dfs(v);
        f[u][0] += minn(f[v][0] , f[v][1] ,f[v][2]);
        f[u][1] += min(f[v][0] , f[v][1]);
        f[u][2] += f[v][1];
        smin (delta , f[v][0] - f[v][1]);
    }
    if(delta > 0) f[u][1] += delta; // indicates that no son chosed the status 0
    f[u][0] += cost[u];
}
int main()
{
    freopen("emperor.in","r",stdin);
    freopen("emperor.out","w",stdout);
    init();
    dfs(root);
    printf("%d",min(f[root][0] , f[root][1])); // mustn't use the father status, 'coz of no existence Last WA !!!
    return 0;
}

你可能感兴趣的:(动态规划,树形dp,动态规划,树形dp)