Noip2003 P1041 传染病控制

Noip2003 提高组 P1041

题意:在一棵树上,传染病每次沿一条边传染一个节点,每次可以切断一条传播路径,求最少的感染数

第i步删的边一定是第i层与第i+1层之间的连边,这样就可以枚举这些删边(删一条边代表将这条边锁链子树的边一同删去),寻找最优解

const int N=310;
const int inf=0x3f3f3f3f;
int n,p,ans=inf,Fa[N];
int head[N],cnt;
bool lc[N][N];//某条边是否可以走
vector<int> dep[N];//第i层的所有连边
struct node{
	int u,v,nxt;
}G[N<<1];
void adde(int u,int v){
	G[++cnt].u=u;
	G[cnt].v=v;
	G[cnt].nxt=head[u];
	head[u]=cnt;
}
//预处理出dep数组与Fa数组
void init(int u,int fa,int d){
	dep[d].push_back(u);
	Fa[u]=fa;
	for(int i=head[u];i;i=G[i].nxt){
		int v=G[i].v;
		if(v!=fa) init(v,u,d+1);
	}
}
//将子树上所有的边打上标记
void dfs(int u,int fa,bool b){
	lc[u][fa]=lc[fa][u]=b;
	for(int i=head[u];i;i=G[i].nxt){
		int v=G[i].v;
		if(v!=fa) dfs(v,u,b);
	}
}
//枚举删边
void work(int d,int cur){
	int sum=0;//统计所有可走的边
	for(int i=0;i<dep[d].size();i++){
		int v=dep[d][i],u=Fa[v];
		if(lc[u][v]) sum++;
	}
	if(sum==0){//若无边可走也即不会再传染,直接与当前最优值比较
		ans=min(ans,cur); return;
	}
	for(int i=0;i<dep[d].size();i++){
		int v=dep[d][i],u=Fa[v];
		if(!lc[v][u]) continue;//删边的范围为所有可走的边
		dfs(v,u,false);
		work(d+1,cur+sum-1);
		dfs(v,u,true);
	}
}

int main(){
	n=read(); p=read();
	for(int i=1;i<=p;i++){
		int u=read(),v=read();
		adde(u,v); adde(v,u);
		lc[u][v]=lc[v][u]=true;
	}
	init(1,0,0);
	work(1,1);
	cout << ans << endl;
	return 0;
} 
posted @ 2019-05-18 21:49  zyh-etr  阅读(167)  评论(0编辑  收藏  举报