Evanyou Blog 彩带

P4645 [COCI2006-2007 Contest#3] BICIKLI

题意翻译

给定一个有向图,n个点,m条边。请问,1号点到2号点有多少条路径?如果有无限多条,输出inf,如果有限,输出答案模10^9的余数。

两点之间可能有重边,需要看成是不同的路径。

题目描述

A bicycle race is being organized in a land far, far away. There are N town in the land, numbered 1 through N. There are also M one-way roads between the towns. The race will start in town 1 and end in town 2. How many different ways can the route be set? Two routes are considered different if they do not use the exact same roads.

输入输出格式

输入格式:

The first line of input contains two integers N and M (1 ≤ N ≤ 10 000, 1 ≤ M ≤ 100 000), the number of towns and roads. Each of the next M lines contains two different integers A and B, representing a road between towns A and B. Towns may be connected by more than one road.

输出格式:

Output the number of distinct routes that can be set on a single line. If that number has more than nine digits, output only the last nine digits of the number. If there are infinitely many routes, output "inf".

输入输出样例

输入样例#1: 
6 7
1 3
1 4
3 2
4 2
5 6
6 5
3 4
输出样例#1: 
6 8
1 3
1 4
3 2
4 2
5 6
6 5
3 4
4 3
输入样例#2: 
3
输出样例#2: 
inf

说明

本题数据已经被更改,无需保留前导0

 

Solution:

  本题Tarjan缩点+拓扑序dp。

  考虑结果为inf的情况,只要1经过一个环再到2就说明有无数条路径。

  于是我们建两幅图,一正一反,分别处理出1能到达的所有点和能到达2的所有点,然后再对原图缩点(小优化是只需要对1能访问的点缩点就好了),枚举每个点作为中间点,判断1能否经过该点到达2且该点在一个环上,若满足条件说明解为inf咯。

  判完inf的情况,说明剩下的图是个DAG了,直接拓扑序dp就好了(注意模数是$1e9$,开始下意识当作$1e9+7$,然后WA了,咕咕咕~)。

代码:

/*Code by 520 -- 9.5*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=200005,mod=1e9;
int n,m,rd[N],bl[N],scc,low[N],dfn[N],siz[N],tot;
int to[N],net[N],h[N],cnt,stk[N],top,ans[N];
int To[N],Net[N],H[N];
bool vis1[N],vis2[N],ins[N];
struct node{
    int u,v;
}e[N];
int gi(){
    int a=0;char x=getchar();
    while(x<'0'||x>'9')x=getchar();
    while(x>='0'&&x<='9')a=(a<<3)+(a<<1)+(x^48),x=getchar();
    return a;
}

il void add(int u,int v){
    to[++cnt]=v,net[cnt]=h[u],h[u]=cnt;
    To[++cnt]=u,Net[cnt]=H[v],H[v]=cnt;   
}

void dfs(int u,bool *vis,int *h,int *to){
    vis[u]=1;
    for(RE int i=h[u];i;i=net[i])
        if(!vis[to[i]]) dfs(to[i],vis,h,to);
}

void tarjan(int u){
    dfn[u]=low[u]=++tot,stk[++top]=u,ins[u]=1;
    for(RE int i=h[u];i;i=net[i])
        if(!dfn[to[i]]) tarjan(to[i]),low[u]=min(low[u],low[to[i]]);
        else if(ins[to[i]]) low[u]=min(low[u],dfn[to[i]]);
    if(dfn[u]==low[u]){
        ++scc;
        while(stk[top+1]!=u)
            bl[stk[top]]=scc,ins[stk[top--]]=0,siz[scc]++;
    }
}

queue<int>q;
int main(){
    n=gi(),m=gi();
    For(i,1,m) e[i].u=gi(),e[i].v=gi(),add(e[i].u,e[i].v);
    dfs(1,vis1,h,to),dfs(2,vis2,H,To);
    if(!vis1[2]) cout<<0,exit(0);
    memset(h,0,sizeof(h)),cnt=0;
    For(i,1,m) if(vis1[e[i].u]&&vis1[e[i].v]) add(e[i].u,e[i].v),rd[e[i].v]++;
    For(i,1,n) if(!dfn[i]&&vis1[i]) tarjan(i);
    if(bl[1]==bl[2]) cout<<"inf",exit(0);
    For(i,1,n) if(vis1[i]&&vis2[i]&&siz[bl[i]]>1) cout<<"inf",exit(0);
    q.push(1),ans[1]=1;
    while(!q.empty()){
        RE int u=q.front();q.pop();
        for(RE int i=h[u];i;i=net[i]){
            ans[to[i]]=(ans[to[i]]+ans[u])%mod;
            if(!--rd[to[i]])q.push(to[i]);
        }
    }
    cout<<ans[2];
    return 0;
}    

 

posted @ 2018-09-05 22:13  five20  阅读(198)  评论(0编辑  收藏  举报
Live2D