拓扑排序用bitset处理相同排名的集合

本文探讨了在有向无环图中使用拓扑排序求解全序的问题,特别是在面对结点rank相同的情况时,引入bitset来高效处理。通过一个具体实例,详细介绍了如何结合bitset与拓扑排序进行节点rank的计算,以及bitset的各种内置方法和位运算的使用。
前言

拓扑排序可以在有向无环图中以偏序求出全序,但是在一些图中,有些结点的rank是一样高的,(除非题目有特殊说明,编号小的rank高等情况),这样是不能求出正确的rank的。这时候,我们可以加入bitset,用bitset处理相同rank的结点集。

bitset

使用头文件 bitset

bitset类似于一个bool类型的数组,存放着01。可以在定义的时候进行初始化操作,可以用下标进行访问,也是从0开始,并且从默认最右边的一位为[0](结合二进制数,其实很人性化),定义、访问及初始化方法如下:

int main()
{
    bitset<10> q(3);
    cout << q << endl;
    for (int i = 0; i < 10; i++)
        cout << q[i] << ' ';
    cout << endl;
    bitset<10> b("1110");
    cout << q << endl;
    /*
Output:
0000000011                                        
1 1 0 0 0 0 0 0 0 0
0000000011
*/
    return 0;
}

bitset的一些内置方法:
s.set():把s所有位初始化为1
s.reset():把s所有位初始化为0
s.set(k):把s的第k位设置为1
s.reset(k):把s的第k位设置为0
s.count():返回1的个数
s.any():返回是否有1
s.none():返回是否没有1

另外bitset支持位运算,这也是它很重要的一个优点。

拓扑排序使用bitset

先上一个例题:核弹剑仙

这题其实就是让你求每个结点的rank,并且可能有并列的情况,这时候我们就可以用bitset和拓扑来进行转移,bitset[i][j]表示结点j是否比i的rank高。
建图的时候u到v的单向路径表示u的rank高于v的rank,这样我们拓扑排序+bitset进行转移即可。

最后配合s.count()进行输出

AC代码:

ll head[1010];
ll ct = 1;
struct node
{
    ll v, next;
} e[2010];
void add(ll u, ll v)
{
    e[ct].v = v;
    e[ct].next = head[u];
    head[u] = ct++;
}

ll degree[1010];
ll n, m;
queue<int> q;
bitset<1010> sum[1010];
void topo()
{
    ll pos;
    for (int j = 1; j <= n; j++)
        if (!degree[j])
            q.push(j);
    while (q.size())
    {
        pos = q.front();
        q.pop();
        degree[pos] = INF;
        for (int i = head[pos]; i; i = e[i].next)
        {
            sum[e[i].v][pos] = 1;    //u比v的rank高
            sum[e[i].v] |= sum[pos]; //使用位运算
            degree[e[i].v]--;
            if (degree[e[i].v] == 0)
                q.push(e[i].v);
        }
    }
}
int main()
{
    scanf("%lld%lld", &n, &m);
    for (int i = 1; i <= m; i++)
    {
        ll a, b;
        scanf("%lld%lld", &a, &b);
        degree[b]++;
        add(a, b);
    }
    topo();
    for (int i = 1; i <= n; i++)
        cout << sum[i].count() << endl;
    return 0;
}
参考资料
  1. C++ bitset——高端压位卡常题必备STL
  2. bitset【C++STL】
# P3116 [USACO15JAN] Meeting Time S ## 题目描述 $\texttt{Bessie}$ 和她的妹妹 $\texttt{Elsie}$ 想从粮仓去她们最喜欢的田地,也就是能够使她们一起从粮仓离开,并且能同一时间到达的田地。 这个农场是由 $N$ 块 $(1\leq N\leq 100)$ 编号为 $1\cdots N$ 的田地构成的,第一块田地就是粮仓,并且第 $N$ 块田地是她们最喜欢的田地。 这个农场建在山的一边,所以,如果 $X < Y$ 的话则满足第 $X$ 块田地的高度要高于第 $Y$ 块田地的高度。在这之中,有 $M$ 条交错纵横的路径将不同的田地连接起来。 不过,显而易见的是,因为每条路都太陡了,所以这些小路只能沿着从高到低的方向走。例如,一条连接第 $5$ 块田地和 $8$ 块田地的小路只能沿着 $5\to 8$ 的方向走,而不能沿着其他方向,因为那样会成为上坡路。每两块田地最多只能有一条路径相连接,所以一定有 $M \leq \dfrac{N(N-1)}{2}$。 有可能的是,$\texttt{Bessie}$ 和 $\texttt{Elsie}$ 两个人走同一条小路会耗费不同的时间;比如,通过同一条小路,$\texttt{Bessie}$ 可能会耗费 $10$ 个单位的时间,而 $\texttt{Elsie}$ 会耗费 $20$ 个单位的时间。 此外,$\texttt{Bessie}$ 和 $\texttt{Elsie}$ 只会在通过连接两块田地的小路时耗费时间——因为她们太匆忙了,在穿过田地时不会耗费任何时间,也从来不在任何地方停下来等待。 现在,请你判断出,能够满足使 $\texttt{Bessie}$ 和 $\texttt{Elsie}$ 同时出发并且同时到达她们喜欢的田地的最短的时间。 ## 输入格式 第一行输入 $N$ 和 $M$,中间用空格分开。 接下来的 $M$ 行,每行有四个整数 $A,B,C,D$,其中,$A$ 和$B(A<B)$ 代表着两块用这条小路连接的田地,$C$ 代表 $\texttt{Bessie}$ 通过这条小路的时间,而 $D$ 代表 $\texttt{Elsie}$ 通过这条小路的时间。$C$ 和 $D$ 均在 $1\cdots100$ 的范围之内。 ## 输出格式 一个整数,输出的是能够使两人同时出发并且同时到达目的地的最短时间,如果没有满足条件的答案,则输出 `IMPOSSIBLE`。 ## 输入输出样例 #1 ### 输入 #1 ``` 3 3 1 3 1 2 1 2 1 2 2 3 1 2 ``` ### 输出 #1 ``` 2 ``` ## 说明/提示 $\texttt{Bessie}$ 在每一条路都比 $\texttt{Elsie}$ 快两倍。 如果 $\texttt{Bessie}$ 经过 $1\to 2\to 3$ 的路线,$\texttt{Elsie}$ 经过 $1\to 3$ 的路线,他们可以同时到达。c++code
03-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hesorchen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值