题意:给定一个有向无环图,其中具有n个点和m条边。已知出度为0的点只有n点。从所有入度为0的点出发到达n,问所有可能路径中,经过某条路的最大次数是多少。
题解:按照拓扑排序的顺序正向走一遍,记录到达某点的路径总数dp数组;从n出发反向走一遍,记录某点出发到终点的总情况数num数组。第二遍扫的时候枚举每条边,求该边对应两点所记录的两个信息之积的最大值。
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
#define INF 0x3fffffff
#define clr(s,t) memset(s,t,sizeof(s));
#define N 5005
int n,m;
struct edge{
int y,next,flag;
}e[50005<<1];
int first[N],d[N],g[N],top,dp[N],num[N];
void add(int x,int y,int flag){
e[top].y = y;
e[top].flag = flag;
e[top].next = first[x];
first[x] = top++;
}
int main(){
int i,a,b,now,res=0;
queue<int> q;
clr(first,-1);
clr(dp, 0);
clr(d,0);
clr(g, 0);
clr(num, 0);
top = 0;
scanf("%d %d",&n,&m);
for(i = 1;i<=m;i++){
scanf("%d %d",&a,&b);
add(a,b,1);
add(b,a,2);
d[b]++;
g[a]++;
}
for(i = 1;i<=n;i++)
if(!d[i]){
q.push(i);
dp[i] = 1;
}
while(!q.empty()){
now = q.front();
q.pop();
for(i = first[now];i!=-1;i=e[i].next){
if(e[i].flag == 2)
continue;
dp[e[i].y] += dp[now];
d[e[i].y]--;
if(!d[e[i].y])
q.push(e[i].y);
}
}
num[n] = 1;
q.push(n);
while(!q.empty()){
now = q.front();
q.pop();
for(i = first[now];i!=-1;i=e[i].next){
if(e[i].flag == 1)
continue;
num[e[i].y] += num[now];
res = max(res,num[now]*dp[e[i].y]);
g[e[i].y]--;
if(!g[e[i].y])
q.push(e[i].y);
}
}
printf("%d\n",res);
return 0;
}