HDOJ 4582 DFS spanning tree

原创 2013年08月12日 08:29:19

题意: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;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

HDU 4582 DFS spanning tree 解题报告(贪心 & 树形DP)

首先声明,这题我是不会的,参考了frog1902的解题报告。http://blog.csdn.net/frog1902/article/details/9921845     当然,她的解题报告一开始...
  • kbdwo
  • kbdwo
  • 2013年08月15日 17:41
  • 1240

hdu4582 DFS spanning tree

给定一个无向图,求出它的DFS生成树。 非树边与树边会构成环,现在选择树上的最少的边数,使得每一个环都至少有一条边被选中。 一个环对应的就是树上的一条路径,因为DFS树的性质这条路径只可能...
  • Sd_Invol
  • Sd_Invol
  • 2013年08月14日 14:21
  • 1405

HDOJ 4582 DFS spanning tree

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

hdu 4582 DFS spanning tree

一开始在有没有横向边的问题上纠结,后来又卡在数据结构的表示上。。。真心菜的不能看,只好从思路到数据结构都借鉴别人的吧 #include #include #include #include ...
  • solotzg
  • solotzg
  • 2014年01月02日 21:03
  • 628

HDOJ 4582: DFS spanning tree

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4582 题目大意: 给出一个有向图。 这个图的前n-1条边构成这个图的一个以节点1为根节点的DFS树...
  • frog1902
  • frog1902
  • 2013年08月12日 12:50
  • 1685

hdu 4582 DFS spanning tree

题意:给出一棵dfs生成树,让你选一些树上的边,使得所有T-Simple Circles至少包含一条你选的边。 思路:由于给出的是dfs生成树,所以这里是没有横叉边的,直觉告诉我们选择的边应该在树上...
  • qian99
  • qian99
  • 2013年09月27日 09:40
  • 629

Hdu4582-DFS spanning tree VS Pku2152-Fire 一类平方级树形最小覆盖问题

/* 题意:某国N个城市,之间树形交通网络。现要在一些城市建消防站,要求:每个城市i要 么有自己的消费站,要么离最近的有消费站的城市的距离不超过Di(各个城市的要求 不尽相同)...
  • yihuikang
  • yihuikang
  • 2013年08月02日 22:16
  • 1077

《PCL点云库学习&VS2010(X64)》Part 41 图形学领域的关键算法及源码链接

《PCL点云库学习&VS2010(X64)》Part 41 图形学领域的关键算法及源码链接 原文链接: Conference papers Graphics Confer...
  • sinat_24206709
  • sinat_24206709
  • 2017年06月06日 10:16
  • 1344

Spanning Tree Group --- part 1

Spanning Tree Group --- part 1概览Spanning Tree Group (STG)会检测并清除桥接或交换网络中的逻辑回路。STG会强制冗余数据路径进入standby (...
  • qipnx
  • qipnx
  • 2007年06月06日 11:32
  • 1448

说说最小生成树(Minimum Spanning Tree)

minimum spanning tree(MST) 最小生成树是连通无向带权图的一个子图,要求 能够连接图中的所有顶点、无环、路径的权重和为所有路径中最小的. graph-cut 对图的一个...
  • gsky1986
  • gsky1986
  • 2015年04月20日 14:24
  • 2435
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:HDOJ 4582 DFS spanning tree
举报原因:
原因补充:

(最多只允许输入30个字)