树状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;
}

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;
}

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;
}

时间: 2024-12-19 12:39:38

树状DP的相关文章

POJ 1155 树状dp

TELE Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3856   Accepted: 2054 Description A TV-network plans to broadcast an important football match. Their network of transmitters and users can be represented as a tree. The root of the tre

洛谷P1122 最大子树和 (树状dp)

题目描述 小明对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题.一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花卉的问题.于是当日课后,小明就向老师提出了这个问题: 一株奇怪的花卉,上面共连有N 朵花,共有N-1条枝干将花儿连在一起,并且未修剪时每朵花都不是孤立的.每朵花都有一个“美丽指数”,该数越大说明这朵花越漂亮,也有“美丽指数”为负 数的,说明这朵花看着都让人恶心.所谓“修剪”,意为:去掉其中的一条枝条,这样一株花就成了两株,扔掉

POJ 1463 树状dp

Strategic game Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 6629   Accepted: 3058 Description Bob enjoys playing computer games, especially strategic games, but sometimes he cannot find the solution fast enough and then he is very sad

POJ 2342 树状dp

Anniversary party Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4606   Accepted: 2615 Description There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure

poj1947--Rebuilding Roads(树状dp)

Rebuilding Roads Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 9496   Accepted: 4316 Description The cows have reconstructed Farmer John's farm, with its N barns (1 <= N <= 150, number 1..N) after the terrible earthquake last May. The

洛谷P2015 二叉苹果树(树状dp)

题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号来描述一根树枝的位置.下面是一颗有4个树枝的树 2 5 \ / 3 4 \ / 1 现在这颗树枝条太多了,需要剪枝.但是一些树枝上长有苹果. 给定需要保留的树枝数量,求出最多能留住多少苹果. 输入输出格式 输入格式: 第1行2个数,N和Q(1<=Q<= N,1<N<=100). N表示树

树状DP入门

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520 题目大意:给定一棵关系树,每个节点有个权值,子节点和父节点不能同时选,问最后能选的最大价值是多少? 解题思路:树形DP入门题.由于子节点与父节点不能同时选,有人可能会用贪心思想,二者选其一肯定最优.其实不然,有可能父节点和子节点都不选,而要选子孙节点.不过只要再往深点想下,就可以得出动态规划的解法.每个节点要么选要么不选,和大多数选不选动归一样,来个dp[i][2],0表示不选,1表示不选,那

树状DP (poj 2342)

题目:Anniversary party 题意:给出N各节点的快乐指数,以及父子关系,求最大快乐指数和(没人职员愿意跟直接上司一起玩): 思路:从底向上的树状DP: 第一种情况:第i个员工不参与,F[i][0] += max(F[k][1], F[k][0]);(k为i的儿子) 第二种情况:第i个员工参与,F[i][1] += F[k][0]; F[i][j]表示第i个员工是否参与: 边界:F[i][0] = 0:F[i][1] = 其快乐指数: #include <iostream> #in

poj2486--Apple Tree(树状dp)

Apple Tree Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7789   Accepted: 2606 Description Wshxzt is a lovely girl. She likes apple very much. One day HX takes her to an apple tree. There are N nodes in the tree. Each node has an amoun

CF1293E-Xenon&#39;s Attack on the Gangs 树状DP

0边把图分成两个部分,这两个部分的路径之间,mex起码为1,都对答案产生1的贡献. 然后1边接在0边旁边,把图分成了更小的两个部分(0,1的两端),和一些不会再产生新的贡献的区域,这两个更小的部分路径之间,mex起码为2,都对答案又产生了1的贡献.(他们在刚刚算mex起码为1的时候,已经贡献过1了,所以再贡献1,mex就起码为2了). 依次类推,我们发现最后只有一条链上的边放置的是有意义的,其他边都可以随便放,反正不会产生贡献. 我们考虑这种情况下如何求解. 如果只考虑一条链,dp[i][j]从