vijos1144小胖守皇宮 [樹規]

描述
huyichen世子事件後,xuzhenyi成了皇上特聘的御前一品侍衛。
皇宮以午門爲起點,直到後宮嬪妃們的寢宮,呈一棵樹的形狀;某些宮殿間可以互相望見。大內保衛森嚴,三步一崗,五步一哨,每個宮殿都要有人全天候看守,在不同的宮殿安排看守所需的費用不同。
可是xuzhenyi手上的經費不足,無論如何也沒法在每個宮殿都安置留守侍衛。
幫助xuzhenyi佈置侍衛,在看守全部宮殿的前提下,使得花費的經費最少。
格式
輸入格式

輸入文件中數據表示一棵樹,描述如下:
第1行 n,表示樹中結點的數目。
第2行至第n+1n+1行,每行描述每個宮殿結點信息,依次爲:該宮殿結點標號i,在該宮殿安置侍衛所需的經費k,該點的兒子數m,接下來m個數,分別是這個節點的m個兒子的標號r1,r2,⋯,rmr1,r2,⋯,rm。
對於一個n個結點的樹,結點標號在1到n之間,且標號不重複。保證經費總和不超過231−1231−1。
輸出格式

輸出文件僅包含一個數,爲所求的最少的經費。
樣例1
樣例輸入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
樣例輸出1[複製]

25
限制
提示
如圖

來源
huyichen

題意:
給出一棵樹和覆蓋某個點的代價,每個點被覆蓋後可以覆蓋與其相連的點但這個效果不再第二次延伸,求最小代價。
分析:
分析狀態可以發現每個點有三種可能:被自己覆蓋,被直接相連子節點覆蓋或被父節點覆蓋,則很容易獲得轉移方程(見程序),需要注意的是,對於由子節點守的情況,需要保證有取到一個f,於是這裏要運用差分的思想,若到了最後f與g的差的最小值還是正數,就說明一次都沒有取到過f,則需要加上差的最小值以保證此點被守到。此法順便可以吧葉子節點的g賦值爲無限大。

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=1500+5;
int n,nod,k[maxn],son[maxn][maxn],rd[maxn],rot,f[maxn],h[maxn],g[maxn];
void dfs(int u)
{
    int tmp=2e9,ok=0;
    for(int i=1;i<=son[u][0];i++){
        int nxt=son[u][i];
        dfs(nxt);
        f[u]+=min(g[nxt],min(h[nxt],f[nxt]));
        g[u]+=min(f[nxt],g[nxt]);
        h[u]+=min(g[nxt],f[nxt]);
        tmp=min(tmp,f[nxt]-g[nxt]);
    }
    if(tmp<0)tmp=0;
    f[u]+=k[u];g[u]+=tmp;
}
void init()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&nod);
        scanf("%d %d",&k[nod],&son[nod][0]);
        for(int i=1;i<=son[nod][0];i++){
            scanf("%d",&son[nod][i]);
            rd[son[nod][i]]++;
        }
    }
}
void work()
{
    for(int i=1;i<=n;i++)if(!rd[i])
        rot=i;
    dfs(rot);
    printf("%d",min(f[rot],g[rot]));
}
int main()
{
    freopen("vijos1144.in","r",stdin);
    freopen("vijos1144.out","w",stdout);
    init();
    work();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章