QZEZOJ 流量控制题解--zhengjun
题目描述
\(FLY\)农场里的奶牛数量越来越多,牧场里通往牛棚的道路越来越拥堵了,为了缓解交通堵塞,\(FLY\)决定找出最拥挤的道路进行处理。
农场可以看成有\(N(1 ≤ N ≤ 5000)\)个点(从1到\(N\)标号),\(M(1≤M≤50000)\)条边的单向图。总牛棚设置在\(N\)号点,其他点均为奶牛们所在的放牧点,每一条道路都由编号较小的路口通向编号较大的路口,所以\(FLY\)不用担心图上会出现环,而且每条道路最终都可以通向牛棚。注意可能有重边。
这张图上存在许许多多通往\(N\)的路径,\(FLY\)需要找到最拥挤的那条道路(最拥挤的道路为通过的路径数量最多的道路)。
保证结果不会超过一个有符号的\(32\) 位整数。
输入
第一行:两个用空格分开的整数:\(N\)和\(M\)
第二行到第\(M\) + 1行:两个用空格分开的整数表示一条道路连接的两个路口的编号
输出
一行:最拥挤的道路上通过的路径数量
样例输入
7 7
1 3
3 4
3 5
4 6
2 3
5 6
6 7
样例输出
4
提示
(最拥挤的道路是(6,7),一共有四条路径:
1→3→4→6→7
1→3→5→6→7
2→3→4→6→7
2→3→5→6→7
拿到这道题,首先想到是直接dfs,找出所有的路径,再求最大值。可这不是正解,我打出来后直接RE,就想其他办法。
思路
一条可以通向总牛棚的路径一定是从一个入度为0的点开始,到\(N\)。那么,一条道路,要找出这条道路通过的路径数量,就相当于找从入度为0的点通向它的路径数和它通向总牛棚的路径数,这条道路路径数量就是两者之和。
代码实现
首先,我们要从所有入度为0的点开始,用一个\(f\)数组记录入度为0的点通往当前节点的路径数,入度为0的点的路径数为1,然后到了一个点时,找到所有能这个点能够直接通向的点,如果这个点的\(f\)数组还没有值,就\(dfs\)这个点,再把这些点的\(f\)数组加起来就可以了。
这样,就将每个点从入度为0的点通向它的路径数记录在\(f\)数组中。
接着,我们从\(N\)号点开始,还是再用一个\(f\)数组记录当前点通往\(N\)号点的路径数,找前面的做法就可以了。
这样,就将每个点通向\(N\)的路径数记录在\(f\)数组中了。
代码
#include<bits/stdc++.h>
#define maxm 500039
#define maxn 50039
#define max(x,y) (x>y?x:y)
using namespace std;
inline void read(int &x)
{
x=0;register int f=1;register char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
x*=f;
}
int n,m,k1,k2,ans;
int x[maxm],y[maxm];
int head1[maxn],head2[maxn],f1[maxn],f2[maxn],r[maxn];
struct zj1{
int to,nex;
}a1[maxm];
struct zj2{
int to,nex;
}a2[maxm];
void add(int x,int y)
{
a1[++k1].to=y;a1[k1].nex=head1[x];head1[x]=k1;
a2[++k2].to=x;a2[k2].nex=head2[y];head2[y]=k2;
}
void dfs1(int x)//入度为0的点通往当前节点的路径数
{
if(!head1[x]){f1[x]=1;return;}//入度为0的点
for(int i=head1[x];i;i=a1[i].nex)
{
if(!f1[a1[i].to])dfs1(a1[i].to);//如果这个点的f数组还没有值,就dfs这个点
f1[x]+=f1[a1[i].to];
}
}
void dfs2(int x)//当前点通往 N号点的路径数
{
if(!head2[x]){f2[x]=1;return;}//N号点
for(int i=head2[x];i;i=a2[i].nex)
{
if(!f2[a2[i].to])dfs2(a2[i].to);//如果这个点的f数组还没有值,就dfs这个点
f2[x]+=f2[a2[i].to];
}
}
int main()
{
read(n);read(m);
for(int i=1;i<=m;i++)
{
read(x[i]);read(y[i]);
add(x[i],y[i]);
}
for(int i=1;i<=n;i++)
if(!f1[i])dfs1(i);//如果入度为0,就dfs这个点
dfs2(n);//dfs N号点
ans=-1;
for(int i=1;i<=m;i++)
ans=max(ans,f1[x[i]]*f2[y[i]]);//求出答案
cout<<ans;
return 0;
}