题解 P4645 【[COCI2006-2007 Contest#3] BICIKLI】
先膜楼下的chen_zhe大佬%%%
这题思路不难,可能是道假紫题。
大体思路如下:
先判断从1到2点是否有无限条路径。什么时候就会有无限条路径呢?不难想到,当出现一个环且从1节点到2节点能经过它时,就会有无数条路径可走。判断是否有环的方法很简单,只需要求强连通分量(tarjan模板不阐述)。
求好之后我们还得判断从1节点到2节点是否可以遍历到一个环,可以用一个BFS来模拟。我们先用BFS求出从1号节点出发能遍历到的所有的点。然后我们建一个反向的图,再用BFS求出在反向图中从2号点出发能遍历到的所有的点。接着判断如果某一个点既可以被2遍历到又能被1遍历到并且它在一个环之内,就说明有无限条路径,输出inf。
最后,我们在用一个BFS求出从1号点到2号点的路径总数即可。
下面有请可爱丑陋的代码酱出场qwq
#include<bits/stdc++.h>
using namespace std;
const int MAXN=101000;
struct edge{
int to,cost;
};
stack<int> s;
int n,m,dfn[MAXN],low[MAXN],color[MAXN],vis[MAXN],used[MAXN],a[MAXN],countt[MAXN],in[MAXN];
int colornum;
vector<int> G[MAXN];
vector<int> rG[MAXN];
inline int read()//读入优化
{
int num=0;
char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9')
{
num=num*10+ch-'0';
ch=getchar();
}
return num;
}
int cnt;
void tarjan(int u)//Tarjan模板,求出强连通分量
{
cnt++;
dfn[u]=low[u]=cnt;
used[u]=true;
s.push(u);
vis[u]=true;
for(int i=0; i<G[u].size(); i++)
{
int v=G[u][i];
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else
{
if(vis[v])
{
low[u]=min(low[u],dfn[v]);
}
}
}
if(dfn[u]==low[u])
{
colornum++;
while(s.top()!=u)
{
int t=s.top();
s.pop();
color[t]=colornum;
vis[t]=false;
}
s.pop();
color[u]=colornum;
vis[u]=false;
}
}
void bfs1(int x)//求出从1号节点出发能遍历到的所有的点
{
memset(used,0,sizeof(used));
queue<int>q;
q.push(x);
used[x]=true;
while(!q.empty())
{
int v=q.front();
q.pop();
for(int i=0; i<G[v].size(); i++)
{
if(!used[G[v][i]])
{
used[G[v][i]]=true;//判断是否能被1遍历到
q.push(G[v][i]);
}
in[G[v][i]]++;
}
}
}
void bfs2(int x)//求出在逆向图中从2号节点出发能遍历到的所有的点
{
memset(vis,0,sizeof(vis));
queue<int>q;
q.push(x);
vis[x]=true;
while(!q.empty())
{
int v=q.front();
q.pop();
for(int i=0; i<rG[v].size(); i++)
{
if(!vis[rG[v][i]])
{
vis[rG[v][i]]=true;//判断是否能被2遍历到
q.push(rG[v][i]);
}
}
}
}
void bfs3(int x)
{
queue<int>q;
q.push(x);
countt[x]=1;
while(!q.empty())
{
int v=q.front();
q.pop();
for(int i=0; i<G[v].size(); i++)
{
if(vis[G[v][i]])
{
countt[G[v][i]]+=countt[v];
countt[G[v][i]]%=1000000000;//取模
if(!--in[G[v][i]]) q.push(G[v][i]);//小优化
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=1; i<=m; i++)
{
int x,y;
x=read(),y=read();
G[x].push_back(y);//邻接表存储
rG[y].push_back(x);//建反向图
}
for(int i=1; i<=n; i++)
if(!dfn[i]) tarjan(i);
bfs1(1);
bfs2(2);
for(int i=1; i<=n; i++)
a[color[i]]++;//统计每个强连通分中节点个数
for(int i=1; i<=n; i++)
if(used[i]&&vis[i]&&a[color[i]]!=1)//可以被2遍历到又能被1遍历到并且在一个环之内
{
cout<<"inf";
return 0;
}
bfs3(1);
cout<<countt[2];
return 0;
}
管理大大求过