poj 2342/3342 树上的带权最大独立集(不与上司去吃饭)

题意:宴会举办者要邀请一批客人,所有客人之间的关系可以看成一棵树,上层的监督下层的。已知直接相邻层的人不能被同时邀请,而且每个人有个欢乐值。问举办者如何邀请客人能满足上述条件,而且使得欢乐值最大。

思路:树形dp(树上的带权最大独立集问题)。从root开始搜索,dp[i][0]表示在以i为root的子树中不邀请i客人达到的最大欢乐值,dp[i][1]表示在以i为root的子树中邀请i客人达到的最大欢乐值。邀请了i,那么i的所有直接下层节点必然不能邀请,未邀请i,其直接下层节点可请可不请。

#include <stdio.h>
#include <string.h>
#define N 6005
#define max(a,b) ((a)>(b)?(a):(b))
struct edge{
	int y,next;
}e[N];
int dp[N][2],s[N],first[N],flag[N];
int n,top;
void add(int x,int y){
	e[top].y = y;
	e[top].next = first[x];
	first[x] = top++;
}
void dfs(int x){
	int i,y;
	dp[x][1] = s[x];
	for(i = first[x];i!=-1;i=e[i].next){
		y = e[i].y;
		dfs(y);
		dp[x][1]+=dp[y][0];
		dp[x][0]+=max(dp[y][0],dp[y][1]);
	}
}
int main(){
	freopen("a.txt","r",stdin);
	while(scanf("%d",&n)!=EOF){
		int i,a,b;
		memset(dp,0,sizeof(dp));
		memset(first,-1,sizeof(first));
		memset(flag,0,sizeof(flag));
		top = 0;
		for(i = 1;i<=n;i++)
			scanf("%d",&s[i]);
		for(i = 1;i<=n;i++){
			scanf("%d %d",&a,&b);
			if(a){
				add(b,a);
				flag[a] = 1;
			}
		}
		for(i = 1;i<=n;i++)
			if(!flag[i])
				break;
		dfs(i);
		printf("%d\n",max(dp[i][0],dp[i][1]));
	}
	return 0;
}

3342:求一棵树的独立数(不带权),并且要求输出取得独立数的方案是否唯一。

方法仍然是树形dp没什么好说,是否唯一也是开一个数组记录即可。子树如果都是唯一的,那么当前也是唯一的;如果子树中有一个不唯一,那么当前不唯一。

#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
#define INF 0x3fffffff
#define clr(s,t) memset(s,t,sizeof(s))
#define N 205
map<string,int> mm;
int n;
struct edge{
    int y,next;
}e[N<<1];
int first[N],top,dp[N][2],flag[N][2];
char s[105],t[105];
void add(int x,int y){
    e[top].y = y;
    e[top].next = first[x];
    first[x] = top++;
}
void dfs(int x,int fa){
    dp[x][1] = 1;
    dp[x][0] = 0;
    for(int i = first[x];i!=-1;i=e[i].next){
        int y = e[i].y;
        if(y != fa){
            dfs(y,x);
            dp[x][1] += dp[y][0];
            if(flag[y][0])
                flag[x][1] = 1;
            dp[x][0] += max(dp[y][1],dp[y][0]);
            if(dp[y][1]==dp[y][0] || (dp[y][1]<dp[y][0]&&flag[y][0]) || (dp[y][1]>dp[y][0]&&flag[y][1]))
                flag[x][0] = 1;
        }
    }
}
int main(){
    while(scanf("%d",&n) && n){
        int i,len = 0;
        clr(first, -1);
        clr(flag, 0);
        top = 0;
        mm.clear();
        scanf("%s",s);
        mm[s] = ++len;
        for(i = 1;i<n;i++){
            scanf("%s %s",s,t);
            if(!mm.count(s))
                mm[s] = (++len);
            if(!mm.count(t))
                mm[t] = (++len);
            add(mm[s],mm[t]);
            add(mm[t],mm[s]);
        }
        dfs(1,0);
        if(dp[1][0]<dp[1][1]){
            printf("%d ",dp[1][1]);
            if(!flag[1][1])
                printf("Yes\n");
            else
                printf("No\n");
        }else if(dp[1][0] == dp[1][1]){
            printf("%d No\n",dp[1][0]);
        }else{
            printf("%d ",dp[1][0]);
            if(!flag[1][0])
                printf("Yes\n");
            else
                printf("No\n");
        }
    }
    return 0;
}


你可能感兴趣的:(poj 2342/3342 树上的带权最大独立集(不与上司去吃饭))