P2002 消息扩散
题目描述
有n个城市,中间有单向道路连接,消息会沿着道路扩散,现在给出n个城市及其之间的道路,问至少需要在几个城市发布消息才能让这所有n个城市都得到消息。
tarjan缩点(因为一个强连通分量内的点只要又一个传到了其他点都传到了,所以可以缩成一个点),然后重新建图,统计out[i]为0的点的数量
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
using namespace std;
const int maxn = 1e5+5;
set<int> st[maxn];
struct Edge{
int u,v,nxt;
}edge[500005];
int head[maxn],tot;
inline void init(){
memset(head,-1,sizeof(head));
tot = 0;
}
inline void addedge(int u,int v){
edge[++tot] = {
u,v,head[u]};
head[u] = tot;
}
bool vis[maxn];
int dfn[maxn],low[maxn],dfnnum,sta[maxn],stalen,num,color[maxn],out[maxn];
void tarjan(int u){
dfn[u] = low[u] = ++dfnnum;
sta[stalen++] = u,vis[u] = true;
for(int i = head[u]; ~i; i = edge[i].nxt){
Edge &e = edge[i];
if(!dfn[e.v]){
tarjan(e.v);
low[u] = min(low[u],low[e.v]);
}else if(vis[e.v]) low[u] = min(low[u],dfn[e.v]);
}
if(dfn[u]==low[u]){
++num; int cur;
do{
cur = sta[--stalen];
vis[cur] = false;
color[cur] = num;
}while(u!=cur);
}
}
int main()
{
init();
int n,m; cin >> n >> m;
for(int i = 0; i < m; ++i){
int u,v; cin >> u >> v;
if(u==v) continue;
addedge(u,v);
}
for(int i = 1; i <= n; ++i){
if(!dfn[i]) tarjan(i);
}
for(int i = 1; i <= n; ++i){
for(int j = head[i]; ~j; j = edge[j].nxt){
int u = color[i],v = color[edge[j].v];
if(u!=v && !st[u].count(v)){
out[v]++;
st[u].insert(v);
}
}
}
int ans = 0;
for(int i = 1; i <= num; ++i){
if(!out[i]) ans++;
}
cout << ans << endl;
return 0;
}
P2169 正则表达式
题目背景
小Z童鞋一日意外的看到小X写了一个正则表达