【图论】拓扑排序
拓扑排序
引入
某街区犯罪率骤然上升,经过探员007的暗地调查,该地存在黑帮组织,调查局打算采取找到黑帮老大并将其监禁的方法,来弱化黑帮势力,但黑帮内部一旦失去老大后,二把手会自动向上补位,现在作为调查局一员的你,请根据一份黑帮内部从属关系的资料,要求把一份监禁顺序名单递交给上级。
理解
一旦黑帮老大被监禁后,二把手的直属上级关系数就要减一(入度减一),直到二把手没有直接上级时(入度为0),二把手晋升为新的黑帮老大。
模板题
拓扑排序的应用
判断是否存在环
- 由于环上任意一点的入度都为0,所以在初始化和运算过程中都不存在加入的可能。所以当被操作的点数小于总点数时,图中存在环(而通常在问题的复原中,环代表这矛盾的存在,即题目无解)
AcWing 1192. 奖金(有差分约束的味道,要max一下)
-
关于拓扑的起点可以灵活一点,可以从更改指向关系(相当于把a吃b变成了b被a吃),如把
add(a,b)
改成add(b,a)
,vec[a].push_back(b)
改成vec[b].push(a)
.同时记得把indegree[a]=b
改成indegree[b]=a;
-
#include<bits/stdc++.h> using namespace std; const int N = 1e4+10; int n,m; int money[N]; int h[N],e[2*N],ne[2*N],idx=0; void add(int a,int b) { e[idx]=b,ne[idx]=h[a],h[a]=idx++; } int in_d[N]; bool topsort() { queue<int > q; for(int i=1;i<=n;i++) { if(in_d[i]==0) { money[i] = 100; q.push(i); } } int cnt=0; while(q.size()) { int t = q.front(); q.pop(); cnt++; for(int i=h[t];~i;i=ne[i]) { int j = e[i]; in_d[j]--; if(in_d[j]==0) { q.push(j); money[j] = max(money[j ] , money[t] + 1); // cout<<j<<" "<<money[j]<<endl; } } } return cnt==n; } int main() { memset(h,-1,sizeof(h)); cin>>n>>m; for(int i=0;i<m;i++) { int a,b; cin>>a>>b; add(b,a); in_d[a]++; } if(!topsort()) { cout<<"Poor Xed"; } else { int total=0; for(int i=1;i<=n;i++) { total=total+money[i]; } cout<<total; } return 0; }
可达性统计(在DAG图中,统计一个点可以到达的后续结点的个数)
Acwing 164 . 可达性统计
前置知识:bitset
给定一张 N个点 M 条边的有向无环图,分别统计从每个点出发能够到达的点的数量。
#include<bits/stdc++.h>
using namespace std;
const int N = 3e4+10;
bitset <N+1> nums[N+1];
vector <int > ans;
vector <int > order;
int n,m;
int h[N],ne[N*2],e[N*2],idx=0;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int in_d[N];
void topsort()
{
queue<int > q;
for(int i=1;i<=n;i++)
{
if(in_d[i]==0)q.push(i);
}
while(q.size())
{
int t = q.front();
q.pop();
order.push_back(t);
for(int i = h[t];~i;i=ne[i])
{
int j = e[i];
if(--in_d[j]==0)
q.push(j);
}
}
}
void process()
{
for(int i=n-1;i>=0;i--)
{
int st = order[i];
for(int j = h[st];~j;j=ne[j])
{
int k=e[j];
nums[st] = nums[st] | nums[k];
}
}
}
void print()
{
for(int i=1;i<=n;i++)
cout<<nums[i].count()<<endl;
}
int main()
{
memset(h,-1,sizeof(h));
memset(in_d,0,sizeof(in_d));
cin>>n>>m;
for(int i=1;i<=n;i++)
{
nums[i].reset();
nums[i].set(i);
}
for(int i=0;i<m;i++)
{
int aa,bb;
cin>>aa>>bb;
add(aa,bb);
in_d[bb]++;
}
topsort();
process();
print();
return 0;
}
其他
- 将函数返回类型改为
bool
- DAG(Directed Acyclic Graph)
- bitset