BZOJ 1638: Cow Traffic 奶牛交通 DFS路径计数

Description

农场中,由于奶牛数量的迅速增长,通往奶牛宿舍的道路也出现了严重的交通拥堵问题.FJ打算找出最忙碌的道路来重点整治. 这个牧区包括一个由M (1 ≤ M ≤ 50,000)条单行道路(有向)组成的网络,以及 N (1 ≤ N ≤ 5,000)个交叉路口(编号为1..N),每一条道路连接两个不同的交叉路口.奶牛宿舍位于第N个路口.每一条道路都由编号较小的路口通向编号较大的路口.这样就可以避免网络中出现环.显而易见,所有道路都通向奶牛宿舍.而两个交叉路口可能由不止一条边连接. 在准备睡觉的时候,所有奶牛都从他们各自所在的交叉路口走向奶牛宿舍,奶牛只会在入度为0的路口,且所有入度为0的路口都会有奶牛. 帮助FJ找出最忙碌的道路,即计算所有路径中通过某条道路的最大次数.答案保证可以用32位整数存储.

Input

第一行:两个用空格隔开的整数:N,M.

第二行到第M+1行:每行两个用空格隔开的整数ai,bi,表示一条道路从ai到bi.

Output

第一行: 一个整数,表示所有路径中通过某条道路的最大次数.

    这个题就是一个路径计数的问题啦。

       显而易见,对于入度为0的那条点,只能向它连接的那一条边,贡献1的流量,根据加法原理,每一个点的流量,等于能到达它的点的流量的和。所以对于我们可以进行dfs,当找到一条入度为0的点时,那么就把它的答案改为一,之后不断回溯,就能找到到达这个点的路径条数了。

       下面的问题就是,如何寻找这条边另外一个端点到终点的路径条数了,与上一段所述方法相同。

       那么最后便是统计每条边的流量,由于题上说了,每条道路都连向终点,所以,根据乘法原理,这条边的流量,也就是方案数,就等于它左端点的方案数乘以它右端点的方案数了。

        注意的就是,如果用邻接矩阵来存的话,如果它的size==0,说明它没有连边,出度为0,所以计算出入度的时候要有一个相当于反向的操作。也因此在代码中dfs2(n)的时候,计算的是从每个入度为0的点,到每一个点的方案数,这一点一定要注意!

       下附AC代码。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#define maxn 50005
using namespace std;
int n,m;
vector<int> edge1[maxn],edge2[maxn];
int cal1[maxn],cal2[maxn];
int x[maxn],y[maxn];
void dfs1(int now)
{
    int len=edge1[now].size();
    if(len==0) 
    {
        cal1[now]=1;
        return;
    }
    for(int i=0;i<len;i++)
    {
        if(cal1[edge1[now][i]]==0)
        dfs1(edge1[now][i]);
        cal1[now]+=cal1[edge1[now][i]];
    }
    return;
}
void dfs2(int now)
{
    int len=edge2[now].size();
    if(len==0) 
    {
        cal2[now]=1;
        return;
    }
    for(int i=0;i<len;i++)
    {
        if(cal2[edge2[now][i]]==0)
        dfs2(edge2[now][i]);
        cal2[now]+=cal2[edge2[now][i]];
    }
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x[i],&y[i]);
        edge1[x[i]].push_back(y[i]);
        edge2[y[i]].push_back(x[i]);
    }
    for(int i=1;i<=n;i++)
    if(cal1[i]==0)
    {
        dfs1(i);
    }
    dfs2(n);
    int ans=0;
    for(int i=1;i<=m;i++)
    ans=max(ans,cal1[y[i]]*cal2[x[i]]);
    printf("%d\n",ans);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值