P2279 [HNOI2003]消防局的设立

是一道非常有意思的。。。。乱搜题

打了个树形dp,将自己的建,不建,次建作为状态

                f[nx][0]=min(f[nx][0],f[v][2]);
		f[nx][0]=min(f[nx][0],f[v][1]);//0为不建,从1建和2借建来 
		f[nx][1]=min(f[nx][1],f[v][0]+1);
		f[nx][1]=min(f[nx][1],f[v][2]+1);//1为建, 
		f[nx][1]=min(f[nx][1],f[v][1]+1);
		f[nx][2]=min(f[nx][2],f[v][1]);//2为借建         

发现没有考虑两个兄弟的情况,然后题解的dp和我的意义完全不一样,我就又写了个贪心:每次找最深的点,在它爷爷上建一个,进行覆盖。最大的收获是fa【i】的使用,利用了树只有一个父亲(指定根),非常便利地找爷爷。也方便上下覆盖,

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
vector <int> son[1002];
int maxn,ans,deep[1002],fa[1002],n;
bool vis[1002];
void dfs(int nx,int d){
	vis[nx]=1;
	if(d==0)	return;
	int si=son[nx].size();
	for(int i=0;i<si;i++){
		int v=son[nx][i];
		dfs(v,d-1);
	}
	dfs(fa[nx],d-1);
}

int main(){
	scanf("%d",&n);
	fa[1]=1;
	for(int i=2;i<=n;i++){
		int opt;
		scanf("%d",&opt);
	//	son[i].push_back(opt);
		son[opt].push_back(i);
		fa[i]=opt;
	}
	for(int i=1;i<=n;i++)
		deep[i]=deep[fa[i]]+1;
	while(1){
		int fl=0;
		for(int i=1;i<=n;i++)
			if(vis[i]==0&&deep[i]>deep[fl])	fl=i;
		if(fl==0)	break;
		dfs(fa[fa[fl]],2);
		ans++;
	}
	printf("%d",ans);
	
	return 0;
}
原文地址:https://www.cnblogs.com/jindui/p/11632087.html