树状DP

紫皮,各种,非原创

树状数组在我的理解就是在决策过程中具有层次关系,像是树一样,具有上下级关系或者上级对上级一定程度的限制条件

 uva 12186

工人的请愿书

下属中不小于 T% 的人签字时会签字递给上级,问至少需要多少人签字才能传给老板

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cmath>

#include <algorithm>

#include <cstdlib>

#include <map>

#include <queue>

#include <vector>



const int MAXN = 100000+ 10;

const double ESP = 10e-8;

const double Pi = atan(1.0) * 4;

const int INF = 0xffffff;

const int MOD = 2012;

typedef long long LL;

using namespace std;

vector<int>sons[MAXN];

int n,T;

int dp(int u){

    if(sons[u].empty()){

        return 1;

    }

    int k = sons[u].size();

    vector<int>d;

    for(int i = 0;i < k;i++){

        d.push_back(dp(sons[u][i]));

    }

    sort(d.begin(),d.end());

    int c = (k*T - 1) / 100+ 1;

    int ans = 0;

    for(int i = 0;i < c;i++){

        ans += d[i];

    }

    return ans;

}

int main(){

    //freopen("input.txt","r",stdin);



    while(~scanf("%d%d",&n,&T)){

        if(!n && !T){

            break;

        }

        for(int i = 0;i <= n;i++){

            sons[i].clear();

        }

        for(int i = 1;i <= n;i++){

            int a;

            scanf("%d",&a);

            sons[a].push_back(i);

        }

        printf("%d\n",dp(0));

    }

    return 0;

}
View Code

 poj 3442 / uva 1220 Party at Hali-Bula

晚会邀请人,但是上下级不能在一起,求最多能邀请多少人,并且方案是否唯一

d(u,1) 邀请了u,所以其下级不能邀请 所以d(u,1) = sum(d(v,0) );

d(u,0) 没有邀请u,所以其下级,可以邀请也可以不邀请 则 d(u,0) = sum{ max( d(v,0),d(v,1) ) };

f(u,0) 为 1表示不唯一,否则唯一

f(u,1) 表示邀请了u,其方案是否唯一,当f(v,0)不唯一时,则f(u,1)必须不唯一

f(u,0) 没邀请 u 的方案是否唯一,如果 d(v,1) == d(v,0) 或者 由其所取的值得f(v)决定

#include <iostream>

#include <cstdio>

#include <cmath>

#include <cstring>

#include <algorithm>

#include <cstdlib>

#include <stack>

#include <cctype>

#include <string>

#include <queue>

#include <map>

#include <set>



using namespace std;



const int INF = 0xffffff;

const double ESP = 10e-8;

const double Pi = 4 * atan(1.0);

const int MAXN =  200 + 10;

const long long MOD =  1000000007;

const int dr[] = {1,0,-1,0,-1,1,-1,1};

const int dc[] = {0,1,0,-1,1,-1,-1,1};

typedef long long LL;



LL gac(LL a,LL b){

   return b?gac(b,a%b):a;

}

int n;

int d[MAXN][2];

int child[MAXN];

bool f[MAXN][2];

int cnt;

map<string,int>m;

vector<int>G[MAXN];

int getNum(string str){

    int a;

    if(m.count(str)){

        a = m[str];

    }

    else{

        a = cnt;

        m[str] = cnt++;

    }

    return a;

}

void dp(int r){

    if(!G[r].size()){ //没有孩子

        d[r][1] = 1;//如果选择r能获得的最大值

        d[r][0] = 0; //如果不选择r获得的最大值

//        f[r][1] = 1;

//        f[r][0] = 1;

        return;

    }

    d[r][1] = 1; //如果选择了r则包含r这个员工

    bool flag = 1;

//    f[r][0] = 1;

    int len = G[r].size();

    for(int l = 0;l < len;l++){

        dp(G[r][l]);

        int i = G[r][l];

        if(f[i][0]){

            f[r][1] = 1;

        }

        d[r][1] += d[i][0];

        if(d[i][0] > d[i][1]){

            d[r][0] += d[i][0];

            if(f[i][0])

                f[r][0] = 1;

        }

        else{

            d[r][0] += d[i][1];

            if(d[i][1] == d[i][0] || f[i][1])

                f[r][0] = 1;

        }

//        if(G[r][i]){

//            dp(i);

//            if(f[i][0]){

//                f[r][1] = 1;

//            }

//            d[r][1] += d[i][0];

//            if(d[i][0] > d[i][1]){

//                d[r][0] += d[i][0];

//                if(f[i][0])

//                    f[r][0] = 1;

//            }

//            else{

//                d[r][0] += d[i][1];

//                if(d[i][1] == d[i][0] || f[i][1])

//                    f[r][0] = 1;

//            }

////            d[r][1] += d[i][0]; //如果选择了r这其下级不能选择

////            if(!f[i][0]){

////                flag = 0;

////            }

////            if(d[i][0] == d[i][1]){

////                f[i][0] = 0;

////                d[r][0] += d[i][0];

////            }

////            else if(d[i][0] > d[i][1]){

////                d[r][0] += d[i][0];

////                if(!f[i][0]){

////                    f[r][0] = 0;

////                }

////            }

////            else{

////                d[r][0] += d[i][1];

////                if(!f[i][1]){

////                    f[r][0] = 0;

////                }

////            }

//

//        }

//    }

//    if(flag){

//        f[r][1] = 1;

    }

    return;

}

int main(){

#ifndef ONLINE_JUDGE

    freopen("inpt.txt","r",stdin);

   // freopen("output.txt","w",stdout);

#endif

    while(~scanf("%d",&n) && n){

        cnt = 1;

        memset(child,0,sizeof(child));

        memset(f,0,sizeof(f));

        memset(d,0,sizeof(d));

        string str1;

        string str2;

        m.clear();

        cin >> str1;

        m[str1] = cnt++;

        int a,b;

        for(int i = 0;i <= n;i++){

            G[i].clear();

        }

        for(int i = 1;i < n;i++){

            cin >> str1 >> str2;

            a = getNum(str1);

            b = getNum(str2);

            G[b].push_back(a);

        }

        dp(1);

        if(d[1][0] == d[1][1]){

            printf("%d No\n",d[1][0]);

        }

        else if(d[1][0] > d[1][1]){

            printf("%d %s\n",d[1][0],!f[1][0]?"Yes":"No");

        }

        else{

            printf("%d %s\n",d[1][1],!f[1][1]?"Yes":"No");

        }

    }

    return 0;

}
View Code

poj 3398 Perfect Service / uva 1218

联通的计算机,从中间抽取几台电脑充当服务器,使每台电脑恰好有一台服务器相连,求最小的服务器数目

d(u,0) u是服务器,其子节点既可以是服务器,也可以不是服务器

d(u,1) u 不是服务器,但是其父亲是服务器,其儿子一定不是服务器

d(u,2) u不是服务器,其父亲也不是服务器,u恰好一个v是服务器

d(u,0) = sum{min(d(v,0),d(v,1)) } + 1;

d(u,1) = sum{d(v,2)};

d(u,2) = sum{d(vv,2)} = min(d(u,1)- d(v,2) + d(v,0)) //其某一个子节点为服务器

因为是无向树所以需要vis标记

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cmath>

#include <cstdlib>

#include <cctype>

#include <algorithm>

#include <vector>



const int MAXN = 10000 + 10;

const int INF = 0xffffff;

const int mod = 1000007;

const double Pi = atan(1.0)*4;

const double ESP = 10e-8;



using namespace std;

vector<int>G[MAXN];

int d[MAXN][4];

bool vis[MAXN];

int n;

void dp(int u){

    vis[u] = 1;

    int len = G[u].size();

    d[u][0] = 1;  //u是服务器,其子节点既可以是服务器,也可以不是,其父节点可以是服务器,也可以不是

    d[u][1] = 0; //u不是服务器,但是u父亲是服务器,所以其子节点都不是服务器

    d[u][2] = INF; // u,和u的父亲都不是服务器,所以u的子节点必须有点是服务器

    vector<int>arr;

    for(int i = 0;i < len;i++){

        int v = G[u][i];

        if(vis[v])

            continue;

        dp(v);

        arr.push_back(v);

        d[u][0] += min(d[v][0],d[v][1]);  // 子节点既可以是服务器又可以不是服务器所以取最小值

        d[u][1] += d[v][2]; // u不是服务器,子节点不是服务器,所以等于d[v][2]父亲和其本身都不是服务器的相加

    }

    len = arr.size();

    for(int i = 0;i < len;i++){

        int v = arr[i];

        d[u][2] = min(d[u][2],d[u][1] - d[v][2] + d[v][0]);

    }

}

int main(){

   // freopen("input.txt","r",stdin);

    while(~scanf("%d",&n)){

        for(int i = 0;i <= n;i++){

            G[i].clear();

        }

        memset(vis,0,sizeof(vis));

        memset(d,0,sizeof(d));

        for(int i = 1;i < n;i++){

            int a,b;

            scanf("%d%d",&a,&b);

            G[b].push_back(a);

            G[a].push_back(b);

        }

        dp(1);

        int ans = INF;

        ans = min(d[1][0],d[1][2]);

        printf("%d\n",ans);

        scanf("%d",&n);

        if(n < 0)

            break;

    }

    return 0;

}
View Code

 

你可能感兴趣的:(dp)