poj 3272

探讨了在一个有向图中,如何计算从所有入度为0的点出发到达指定点的所有可能路径中,每条边被经过的最大次数。通过构建双向图并使用动态规划方法求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这题蛮有意思的吗

所以来写个博客

题意: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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值