UVa1220

题意:
公司里有n个人形成一个树状结构,即除了老板以外每个员工都有唯一的直属上司。要求选尽量多的人,但不能同时选择一个人和他的直属上司。输出最多能选多少人并判断是否唯一。

思路:树的最大独立集问题。就是需要额外判定是否是唯一的。
d[u][1]表示以u为根的子树中,选u点能得到的最大人数,f[u][1]判断这种方案是否唯一。
d[u][0]表示以u为根的子树中,不选u点能得到的最大人数,f[u][0]判断这种方案是否唯一。
有了这个状态定义,转移就不难了。

对于d[u][1],因为u选了,所以u的子结点都不能选,所以此时d[u][1]=sum(d[v][0]|v是u的子节点)。只有当f[v][0]全都唯一时,f[u][1]才唯一。

对于d[u][0],因为u没有选,所以此时u的子节点可选可不选,挑选出最大的那个。转移方程就是d[u][0]=sum(max(d[v][0],d[v][1]))。唯一性判定:如果有某个子节点d[s][0] = d[s][1],取不取都可以,说明不唯一;其次,对于max取到的那个值对应的 f = 0 的话,也不唯一。

少写了一行,卡了40min,我也很无奈呀哈哈。

#include 
#include  
#include 
#include 
#include 
#include 
using namespace std;

const int N = 200+5;
vector son[N];
map mp;

int d[N][2], f[N][2], n;

void init(){
	mp.clear();
	for(int i = 0; i < n; ++i) {
		son[i].clear();
		f[i][0] = 1; f[i][1] = 1;
	}
	memset(d,0,sizeof(d));
	string s1 , s2 ; 
	int cnt = 0;
	cin>>s1;
	//printf("%s\n",s1);
	mp[s1] = cnt++;
	for(int i = 1; i < n; ++i){
		cin>>s1; cin>>s2;
		if(mp.find(s1) == mp.end()) mp[s1] = cnt++;
		if(mp.find(s2) == mp.end()) mp[s2] = cnt++;
		son[mp[s2]].push_back(mp[s1]);
	}
}

void solve(int u){
	if(son[u].empty()) {
		d[u][1] = 1; d[u][0] = 0;
		return;
	}
	int k = son[u].size();
	
	for(int i = 0; i < k; ++i){
		int s = son[u][i];
		solve( s );			// 递归计算孩子节点 
		// 如果选u
		d[u][1] += d[s][0]; //不能选他的孩子
		if (!f[s][0])    f[u][1] = 0; //一旦有子节点不唯一,它也不唯一
		// 如果不选 u,孩子可选可不选,d[u] += max( d[s][0], d[s][1] ); 
		if(d[s][0] > d[s][1]){
			d[u][0]+= d[s][0];
			if(f[s][0] == 0) f[u][0] = 0;
		}
		else {
			d[u][0]+= d[s][1];
			if(f[s][1] == 0) f[u][0] = 0;
			if(d[s][0] == d[s][1]) f[u][0] = 0;
		}
	}
	++d[u][1]; // 加上u自身 
}

void print_ans(){
	
	if(d[0][1] > d[0][0]){
		printf("%d ",d[0][1]);
        if(f[0][1])
            printf("Yes\n");
        else
            printf("No\n");
    }
    else if(d[0][1] < d[0][0]){
    	printf("%d ",d[0][0]);
        if(f[0][0])
            printf("Yes\n");
        else
            printf("No\n");
    }
    else{
    	printf("%d ",d[0][1]);
    	printf("No\n");
	}
        
}

int main()
{
	
	
	//freopen("in.txt","r",stdin);
	while(scanf("%d",&n) == 1&&n){
		init();
		solve(0);
		print_ans();
	}

	return 0;
}


你可能感兴趣的:(Practice,动态规划)