交通 | ||||||
| ||||||
Description | ||||||
一个农场主有一块草地和一些奶牛,因为在将奶牛赶回牛棚的时候会很拥挤,所以他决定做一个研究,找到最容易“交通堵塞”的位置。 它的农场有M条单向通行的道路和N个路口,用1——N表示,牛棚用N表示,所有的道路之间不构成回路并且全部可以通向牛棚,两个路口之间可能有不止一条直接相连的路,现在他需要知道从所有起点到达终点的路径中经过最多的边经过的次数 | ||||||
Input | ||||||
第一行:N和M表示交点数和道路数 N<5000 M<50000 第2行到第M+1行:每行两个数,表示两个有道路相连的交点 | ||||||
Output | ||||||
输入被经过次数最多的一条边被经过的次数。 | ||||||
Sample Input | ||||||
7 7 1 3 3 4 3 5 4 6 2 3 5 6 6 7 | ||||||
Sample Output | ||||||
4 | ||||||
Hint | ||||||
1 3 4 6 7 1 3 5 6 7 2 3 4 6 7 2 3 5 6 7 6 ->7边被经过了4次 |
思路:
一个有向图的统计数量问题,考虑拓扑排序过程中Dp.
设定Dp【2】【i】;
其中:
①dp【0】【i】表示正向建图,跑到点i的方案数。
②dp【1】【i】表示反向建图,跑到点i的方案数。
状态转移只要累加即可:
dp【d】【v】+=dp【d】【u】;
那么Ans=max(Ans,dp【0】【u】*dp【1】【v】);
Ac代码:
#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
using namespace std;
int degree[65005];
int p[65005][2];
vector<int>mp[65005];
int dp[3][65005];
int n,m;
void Top_Dp(int d)
{
queue<int >s;
for(int i=1;i<=n;i++)
{
if(degree[i]==0)s.push(i),dp[d][i]=1;
}
while(!s.empty())
{
int u=s.front();
s.pop();
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i];
dp[d][v]+=dp[d][u];
degree[v]--;
if(degree[v]==0)
{
s.push(v);
}
}
}
}
void Slove()
{
memset(degree,0,sizeof(degree));
for(int i=1;i<=n;i++)mp[i].clear();
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
mp[x].push_back(y);
degree[y]++;
p[i][0]=x;
p[i][1]=y;
}
Top_Dp(0);
}
void RSlove()
{
memset(degree,0,sizeof(degree));
for(int i=1;i<=n;i++)mp[i].clear();
for(int i=1;i<=m;i++)
{
int x=p[i][1];
int y=p[i][0];
mp[x].push_back(y);
degree[y]++;
}
Top_Dp(1);
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(dp,0,sizeof(dp));
Slove();
RSlove();
int output=0;
for(int i=1;i<=m;i++)
{
output=max(output,dp[0][p[i][0]]*dp[1][p[i][1]]);
}
printf("%d\n",output);
}
}