链式前向星
最近看图论的板子总是有这种代码
struct Edge{
int next; // 下一条边的下标
int to; // 当前边的指向
int w; // 当前边的权值
};
Edge edge[maxn*2];
int tot; // 当前边的下标
void addEdge(int u,int v,int w){
edge[++tot].next = head[u];
edge[tot].to = v;
edge[tot].w = w;
head[u] = tot; // 头插法
}
实质就是链表的运用.
用(Edge.next)代表指向下一条边的指针,(head[u])为节点(u)的头节点,每次加入新边时用头插法.
遍历点(u)可用
for(int i = head[u];i;i = edge[i].next)
题目: luogo P2661 信息传递
- 题目大意: 每个点只有一个出度,求最短环(必存在)
- 思路: (Tarjan)判环,每次跑(dfs)时将所有节点加入栈中,如果新节点已经在栈中,则存在环,从栈中找到新节点,距离栈顶的距离即为环长.
#include<bits/stdc++.h>
#define ll long long
#define FOR(i,n) for(int i =1; i <= n;++i )
#define FOR0(i,n) for(int i =0; i < n;++i )
#define inf 0x3f3f3f3f
#define EPS (1e-8)
#define ALL(T) T.begin(),T.end()
using namespace std;
const int maxn = 200010;
int n;
inline int input(){
int res = 0;
char c;
c = getchar();
while('0' <= c && c<='9'){
res = res*10 + (c-'0');
c = getchar();
}
return res;
}
struct Edge{
int next;
int to;
};
Edge edge[maxn];
int head[maxn];
int cnt;
void addEdge(int u,int v){
edge[++cnt].next = head[u];
edge[cnt].to = v;
head[u] = cnt;
}
int vis[maxn];
int instack[maxn];
stack<int> s;
int ans = inf;
bool dfs(int u){
if(!instack[u] && !vis[u]){
bool sign = false;
instack[u] = 1;
vis[u] = 1;
s.push(u);
for(int i=head[u];i;i=edge[i].next){
sign |= dfs(edge[i].to);
// if(sign) return sign;
}
return sign;
}else{
if(s.empty()){ return false;}
int to = s.top();
int idx = 0;
while(to!=u){
s.pop();
idx++;
if(s.empty()){
return false;
}
to = s.top();
}
ans = min(ans,idx+1);
return true;
}
}
int main(){
n = input();
int to;
FOR(i,n){
to = input();
addEdge(i,to);
}
FOR(i,n){
if(!vis[i]){
dfs(i);
while(!s.empty()) s.pop();
}
}
printf("%d
",ans);
return 0;
}
所有节点只被访问一次即可每次memset(vis)结果TLE了QAQ,其实这道题还有更简单的写法,不过纯属练手了.