这题蛮有意思的吗
所以来写个博客
题意:n个点m条边的有向图,从所有入度为0的点出发到达n,问所有可能路径中,经过的某条路的最大次数是多少。边全是由标号小的到标号大的。
一开始的想法?暴搜吧,所有路径统计一下经过的边
然后1 ≤ N ≤ 5,000 1 ≤ M ≤ 50,000
虽说以usaco的数据不一定超市,但是我们姑且按数据范围认为超时吧
那怎么做呢?怎么做呢》怎么做呢?漫长的思考过程开始了。。
于是决定手动模拟一遍。
所以我们发现 dp着算一下从起点到每个节点的路径数量和从终点到前面的每个点的数量。
那怎么算呢?
这个点有几个连向前边的点的边就加几次。主要图要双反建图。
看代码吧!
没过阳历的原因: ij编号再一次写错。。
#include<cstdio>
#include<algorithm>
#include<cstring>
//by mars_ch
using namespace std;
struct data
{
int f,t,c;
int nxt;
}e[50005],b[50005];
int first[5005],head[5005];
int f[5005],g[5005];
int vis[5005];
int n,m,tot,cnt;
void add1(int a,int b)
{
e[++tot].f=a;
e[tot].t=b;
e[tot].nxt=first[a];
first[a]=tot;
}
void add2(int a,int ba)
{
b[++cnt].f=a;
b[cnt].t=ba;
b[cnt].nxt=head[a];
head[a]=cnt;
}
int main()
{
scanf("%d%d",&n,&m);
memset(first,-1,sizeof(first));
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add1(a,b);
add2(b,a);
vis[b]=1;
}
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
f[i]=1;
}
else
{
for(int j=head[i];j!=-1;j=b[j].nxt)
{
int v=b[j].t;
f[i]+=f[v];
}
}
}
g[n]=1;
for(int i=n;i>=1;i--)
{
for(int j=first[i];j!=-1;j=e[j].nxt)
{
int v=e[j].t;
g[i]+=g[v];
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=first[i];j!=-1;j=e[j].nxt)
{
ans=max(ans,f[i]*g[e[j].t]);
}
}
printf("%d\n",ans);
return 0;
}