首页 > 其他 > 详细

Noip2003 P1041 传染病控制

时间:2019-05-18 22:06:07      阅读:150      评论:0      收藏:0      [点我收藏+]

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

Noip2003 P1041 传染病控制

原文:https://www.cnblogs.com/zhangyuhang253/p/10887260.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!