分析
拓扑序本质上就是一个先后顺序,通过入度的区别来先后入队,使得入队的顺序保证一个严格的递增。
例题
acwing 1192.奖金
通过拓扑序分析就行,既可以判环也可以判是否联通
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5,M = 2 * 1e4 + 5;
int din[N];
int e[M],ne[M],h[N],idx;
int salary[N];
int n,m;
void add(int fr,int to){
idx ++;
e[idx] = to;
ne[idx] = h[fr];
h[fr] = idx;
}
bool topsort(){
queue <int> q;
int cnt = 0;
for(int i = 1;i <= n;i ++){
if(! din[i])
q.push(i),salary[i] = 100,cnt ++;
}
while(! q.empty()){
int f = q.front();
q.pop();
for(int i = h[f];i;i = ne[i]){
-- din[e[i]];
if(din[e[i]] == 0){
salary[e[i]] = salary[f] + 1;
cnt ++;
q.push(e[i]);
}
}
}
return cnt == n;
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i <= m;i ++){
int a,b;
scanf("%d%d",&a,&b);
din[a] ++;
add(b,a);
}
if(! topsort()){
puts("Poor Xed");
exit(0);
}else{
int res = 0;
for(int i = 1;i <= n;i ++)
res += salary[i];
cout << res;
}
return 0;
}
可达性统计
先拓扑序再用bitset统计,思路码一下
#include <bits/stdc++.h>
using namespace std;
const int N = 3e4 + 5;
int e[N],ne[N],h[N],idx;
int a[N];
int din[N];
int cnt;
int n,m;
bitset <N> f[N];
void add(int fr,int to){
idx ++;
e[idx] = to;
ne[idx] = h[fr];
h[fr] = idx;
}
void topsort(){
queue <int> q;
for(int i = 1;i <= n;i ++)
if(! din[i])
q.push(i);
while(! q.empty()){
int f = q.front();
q.pop();
a[++ cnt] = f;
for(int i = h[f];i;i = ne[i]){
din[e[i]] --;
if(! din[e[i]])
q.push(e[i]);
}
}
}
int main(){
cin >> n >> m;
for(int i = 1;i <= m;i ++){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
din[b] ++;
}
topsort();
for(int i = cnt;i >= 1;i --){
int k = a[i];
f[k][k] = 1;
for(int j = h[k];j;j = ne[j])
f[k] |= f[e[j]];
}
for(int i = 1;i <= n;i ++)
cout << f[i].count() << endl;
return 0;
}
acwing.456 车站分级
这道题目,原先我在洛谷做过,当时用暴力连边跑拓扑的方法通过了,但其实复杂度有点高,假设有1000个点,每条车站就要连2e4条边左右,一共就要连2e7条边,复杂度非常高。但是通过建立一个虚点,每条车站至多只需要连1e3条边,一下子少了很多。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 5,M = 1e6 + 5;
int e[M],ne[M],w[M],h[N],idx;
bool stop[N];
int din[N],ans[N],cnt;
int f[N];
int n,m;
void add(int fr,int to,int dis){
din[to] ++;
idx ++;
e[idx] = to;
ne[idx] = h[fr];
h[fr] = idx;
w[idx] = dis;
}
void toposort(){
queue <int> q;
for(int i = 1;i <= n + m;i ++)
if(! din[i])
q.push(i);
while(! q.empty()){
int fr = q.front();
q.pop();
ans[++ cnt] = fr;
for(int i = h[fr];i;i = ne[i]){
din[e[i]] --;
if(! din[e[i]]){
q.push(e[i]);
}
}
}
}
int main(){
cin >> n >> m;
for(int i = 1;i <= m;i ++){
int x;
scanf("%d",&x);
memset(stop,false,sizeof stop);
int start = 1e3 + 5;
int end = 0;
for(int j = 1;j <= x;j ++){
int tmp;
cin >> tmp;
stop[tmp] = true;
start = min(start,tmp);
end = max(end,tmp);
}
for(int j = start;j <= end;j ++){
if(stop[j])
add(j,n + i,0);
else
add(n + i,j,1);
}
}
toposort();
for(int i = 1;i <= n + m;i ++)
f[i] = 1;
int maxn = 0;
for(int i = 1;i <= cnt;i ++){
int k = ans[i];
for(int j = h[k];j;j = ne[j]){
f[e[j]] = max(f[e[j]],f[k] + w[j]);
}
}
for(int i = 1;i <= n;i ++)
maxn = max(maxn,f[i]);
cout << maxn;
}