拓扑排序

1、hdu 4324

题目要求假如a到b没有边,那么b到a一定有边,且两点之间只可能有一条边。根据这个要求,我们可以知道,只要图中存在环,那么就一定存在3元环。那么,只要用拓扑排序删除入度为0的节点,计算剩下的节点就可以了。

2、hdu 2647

反向建边,要注意的是,如果a -> b,c -> b,那么要从a和c中选择一个最大的。这里点太多,需要用邻接表来表示。

3、hdu 4109

跟hdu 2647题相似,不用反向建边,一个结点的时间,是所有与其相接的边的头结点(u - > v,u为头,v为尾)的时间加上它的安全距离的最大值。

4、hdu 1285 3342 2094

模板题

5、hdu 2497

这题是单纯的拓扑排序,但是数据量太大,点和边数最大都有100W,首先需要用邻接表来存储。第一次提交时用了下面这段代码,超时。

void sort()
{
    for(int i = 1;i <= vertex;i++)
    {
        int j = 1;
        while(j <= vertex && indegree[j])
            j++;
        if(j > vertex)
        {
            puts("IMPOSSIBLE");
            return;
        }
        indegree[j]--;
        result[i] = j;
        j = head[j];
        while(j != -1)
        {
            indegree[adjlist[j].v]--;
            j = adjlist[j].next;
        }
    }
    for(int i = 1;i <= vertex;i++)
        printf("%d\n",result[i]);
}
外层循环一定是vertex(点的个数)次,再看内层循环,找入度为0的点,每次都需要遍历indegree[]数组,只要数据强一点,那么几乎需要vertex * vertex的时间。所以,这里可以用队列优化一下。将入度为0的点入队,那么找入度为0的点的操作就可以在O(1)内完成。

void sort()
{
    while(!Q.empty())
        Q.pop();
    for(int i = 1;i <= vertex;i++)
        if(!indegree[i])
            Q.push(i);
    for(int i = 1;i <= vertex;i++)
    {
        int j;
        if(Q.empty())
        {
            puts("IMPOSSIBLE");
            return;
        }
        j = Q.front();
        Q.pop();
        indegree[j]--;
        result[i] = j;
        j = head[j];
        while(j != -1)
        {
            indegree[adjlist[j].v]--;
            if(!indegree[adjlist[j].v])
                Q.push(adjlist[j].v);
            j = adjlist[j].next;
        }
    }
    for(int i = 1;i <= vertex;i++)
        printf("%d\n",result[i]);
}
另外,求拓扑排序还有深搜的方法。《算法导论》上有段伪代码,写明了对于有向无环图求拓扑排序的方法:每次深搜一个未访问的结点,点出栈顺序的逆顺就是我们所求的拓扑排序。但现在的问题是,我们的图可能是有环的,那么,用深搜怎么判断有环?其实,《算法导论》也给我们指明了方法:在深搜时,我们可以用访问的结点进行染色:初始时,所有结点都是白色的,在搜索一个点时,首先将这个点染成灰色,然后在出栈(即这个点DFS结束时)时将这个点染成黑色。按这种方法,如果当前的点跟接下来要访问的点的颜色相同,那么就说明是有环的。用深搜的话,每个点只访问一次,每条边也只访问一次,所以时间复杂度为O(v + e)。

int head[N],result[N],indegree[N],visited[N];
queue<int> Q;
struct Node
{
    int next;
    int v;
    Node(){};
    Node(int a,int b):next(a),v(b){}
}adjlist[N];

struct Graph_Topology
{
    int vertex,edge,num;
    bool circle;
    int flag;
    void init(int n)
    {
        vertex = n,edge = 0;
        memset(indegree,0,sizeof(indegree));
        memset(visited,0,sizeof(visited));
        for(int i = 0;i <= vertex;i++)
            head[i] = -1;
        num = 0;
        circle = false;
    }

    void insert(int u,int v)
    {
        /*
        int i;
        for(i = head[u];i != -1;i = adjlist[i].next)
            if(adjlist[i].v == v)
                break;
        if(i != -1)
            return;
            */
        adjlist[edge] = Node(head[u],v);
        head[u] = edge++;
        indegree[v]++;
    }

    void sort()
    {
        while(!Q.empty())
            Q.pop();
        for(int i = 1;i <= vertex;i++)
            if(!indegree[i])
                Q.push(i);
        for(int i = 1;i <= vertex;i++)
        {
            int j;
            if(Q.empty())
            {
                puts("IMPOSSIBLE");
                return;
            }
            j = Q.front();
            Q.pop();
            indegree[j]--;
            result[i] = j;
            j = head[j];
            while(j != -1)
            {
                indegree[adjlist[j].v]--;
                if(!indegree[adjlist[j].v])
                    Q.push(adjlist[j].v);
                j = adjlist[j].next;
            }
        }
        for(int i = 1;i <= vertex;i++)
            printf("%d\n",result[i]);
    }

    void DFS()
    {
        for(int i = 1;i <= vertex;i++)
            if(!visited[i])
            {
                //flag = i;
                DFS_Visit(i);
                if(circle)
                {
                    puts("IMPOSSIBLE");
                    return;
                }
            }
        for(int i = num;i >= 1;i--)
            printf("%d\n",result[i]);
    }

    void DFS_Visit(int x)
    {
        if(circle)
            return;
        visited[x] = GREY;
        for(int i = head[x];i != -1;i = adjlist[i].next)
            if(!visited[adjlist[i].v])
                DFS_Visit(adjlist[i].v);
            else if(visited[adjlist[i].v] == visited[x])
            {
                circle = true;
                return;
            }
        visited[x] = BLACK;
        result[++num] = x;
    }
};
6、hdu 1811

对相等的边合并成一个点,并用这个点进行拓扑排序的计算。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值