关闭

HDOJ 4582 DFS spanning tree

1373人阅读 评论(0) 收藏 举报
分类:

题意:n个点,m条边的无向图,通过DFS遍历,m条边中前面的n-1条边形成深度优先生成树,后面的自然就是形成环(没有自环)。问从DFS生成树中最少选择多少边,能够使得所有的环都至少有一条边在你选择的集合中。

题解:

考虑DFS生成树,必然没有横叉边(即一个孩子都另一个孩子的边,要不DFS就应该遍历过去),所有的环都是一个结点与它祖先结点的边形成的。

那么这题做法就是进行一次DFS遍历,在回溯的时候,到了now这个结点,那么从他引出的所有后m-n+1条边中,到达深度更深的那些边,也就是如果有now->to这么一条边且dep[now]<dep[to],那么在now结点上面选择边都不会影响到这一条边所形成的环,就意味着必须选择now到to之间的一条边。

由于是回溯时处理,所以需要判断是否now~to之间已经有边被选择了,那么我们考虑如果没有被选择,即现在需要进行选边操作:

有回溯处理操作可以看出,所有深度大于now的出发结点的边所形成的环都已经被处理了,没处理的边就只能是终点在now~to之间,且起点在now之上的边了,任意一种这种边必然会经过now->son,son代表从now到to所经历的第一个结点,那么删除这条边就是使得环减少最多的方案。这种贪心策略之所以正确,是因为在必然要选边的时候选择了能使得环数减少最多的边,选择其他边意味着后面会有一些环还需要选择边。

具体实现的话,就是先对DFS生成树进行树链剖分,生成一个树状数组,某个结点等于1意味着它到它父亲结点的边被选择了,判断now~to是否有边被选择,就是看树状数组相应区间是否有至少一个1,就是和是否大于0.

选择边now~to之间的边就是选择now到to经历的第一条边,就是把now结点的下一个结点在树状数组对应位置+1.

总体复杂度就是:

树链剖分:O(n)

DFS处理:O(n)

查询操作:O (m*logn*logn)

选边操作:O(m*logn*logn)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3005,M=40005;
int ar[N];
inline int lowbit(int x){
    return x&-x;
}
int sum(int i){
    int s=0;
    for(;i>0;s+=ar[i],i-=lowbit(i));
    return s;
}
void add(int i){
    for(;i<N;ar[i]+=1,i+=lowbit(i));
}
int check(int l,int r){
    if(l>r)return 0;
    return sum(r)-sum(l-1);
}
struct Edge{
    int to,nxt;
};
struct Graph{
    int head[N],nc;
    Edge edge[M*2];
    void Init(){
        memset(head,-1,sizeof(head));
        nc=0;
    }
    void Add(int a,int b){
        edge[nc].to=b;edge[nc].nxt=head[a];head[a]=nc++;
    }
    void AddTwo(int a,int b){
        edge[nc].to=b;edge[nc].nxt=head[a];head[a]=nc++;
        edge[nc].to=a;edge[nc].nxt=head[b];head[b]=nc++;
    }
}T,G;
struct STK_Heavy{//now,fa,e,dep
    int now,fa,e,dep;
    STK_Heavy(){}
    STK_Heavy(int _n,int _f,int _e,int _d){
        now=_n,fa=_f,e=_e,dep=_d;
    }
}Hstk[N*2];
struct STK_Create{//now,ac,e
    int now,ac,e;
    STK_Create(){}
    STK_Create(int _n,int _a,int _e){
        now=_n,ac=_a,e=_e;
    }
}Cstk[N*2];
int dep[N],anc[N],pa[N],tid[N],heavy[N],size[N],ID,n,m;
bool mark[N];
void DFS_Heavy(int root){
    int top=0;
    memset(mark,false,sizeof(mark));
    Hstk[top]=STK_Heavy(root,-1,T.head[root],0);
    while(top>=0){
        STK_Heavy elem=Hstk[top];
        if(!mark[elem.now]){
            mark[elem.now]=true;
            size[elem.now]=1;
            heavy[elem.now]=-1;
            pa[elem.now]=elem.fa;
            dep[elem.now]=elem.dep;
        }
        if(elem.e==-1){
            if(top){
                size[elem.fa]+=size[elem.now];
                if(heavy[elem.fa]==-1||size[heavy[elem.fa]]<size[elem.now]){
                    heavy[elem.fa]=elem.now;
                }
            }
            top--;
            continue;
        }
        int to=T.edge[elem.e].to;
        Hstk[top].e=T.edge[elem.e].nxt;
        if(mark[to])continue;
        Hstk[++top]=STK_Heavy(to,elem.now,T.head[to],elem.dep+1);
    }
}
void DFS_Create(int root){
    int top=0;
    Cstk[0]=STK_Create(root,root,T.head[root]);
    memset(mark,false,sizeof(mark));
    while(top>=0){
        STK_Create elem=Cstk[top];
        if(!mark[elem.now]){
            mark[elem.now]=true;
            tid[elem.now]=++ID;
            anc[elem.now]=elem.ac;
            if(heavy[elem.now]!=-1){
                Cstk[++top]=STK_Create(heavy[elem.now],elem.ac,T.head[heavy[elem.now]]);
                continue;
            }
        }
        if(elem.e==-1){
            top--;
            continue;
        }
        int to=T.edge[elem.e].to;
        Cstk[top].e=T.edge[elem.e].nxt;
        if(mark[to])continue;
        Cstk[++top]=STK_Create(to,to,T.head[to]);
    }
}
bool Query(int f,int s){
    while(anc[f]!=anc[s]){
        int fs=anc[s];
        if(check(tid[fs],tid[s])!=0)return true;
        s=pa[fs];
    }
    if(f==s)return false;
    else if(check(tid[f]+1,tid[s])!=0)return true;
    else return false;
}
void Set(int f,int s){
    int p;
    while(anc[f]!=anc[s]){
        s=pa[p=anc[s]];
    }
    if(s==f){
        add(tid[p]);
    }
    else{
        add(tid[f]+1);
    }
}
void Tree_Chain(){
    memset(ar,0,sizeof(ar));
    ID=0;
    DFS_Heavy(1);
    DFS_Create(1);
}
int ans;
void dfs(int now){
    mark[now]=true;
    for(int i=T.head[now];i!=-1;i=T.edge[i].nxt){
        int to=T.edge[i].to;
        if(mark[to])continue;
        dfs(to);
    }
    for(int i=G.head[now];i!=-1;i=G.edge[i].nxt){
        int to=G.edge[i].to;
        if(!Query(now,to)){
            Set(now,to);
            ans++;
        }
    }
}
int main(){
    int a,b;
    while(scanf("%d%d",&n,&m)!=EOF){
        if(n==0&&m==0)break;
        T.Init();
        G.Init();
        for(int i=1;i<=n-1;i++){
            scanf("%d%d",&a,&b);
            T.AddTwo(a,b);
        }
        Tree_Chain();
        for(int i=n;i<=m;i++){
            scanf("%d%d",&a,&b);
            if(dep[a]>dep[b])swap(a,b);
            G.Add(a,b);
        }
        memset(mark,false,sizeof(mark));
        ans=0;
        dfs(1);
        printf("%d\n",ans);
    }
    return 0;
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:77778次
    • 积分:1304
    • 等级:
    • 排名:千里之外
    • 原创:52篇
    • 转载:0篇
    • 译文:0篇
    • 评论:20条
    最新评论