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;
}
原文:https://www.cnblogs.com/zhangyuhang253/p/10887260.html