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;
} 

转载于:https://www.cnblogs.com/zhangyuhang253/p/10887260.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值