拓扑排序/DP【洛谷P2883】 [USACO07MAR]牛交通Cow Traffic

P2883 [USACO07MAR]牛交通Cow Traffic

随着牛的数量增加,农场的道路的拥挤现象十分严重,特别是在每天晚上的挤奶时间。为了解决这个问题,FJ决定研究这个问题,以能找到导致拥堵现象的瓶颈所在。

牧场共有M条单向道路,每条道路连接着两个不同的交叉路口,为了方便研究,FJ将这些交叉路口编号为1..N,而牛圈位于交叉路口N。任意一条单向道路的方向一定是是从编号低的路口到编号高的路口,因此农场中不会有环型路径。同时,可能存在某两个交叉路口不止一条单向道路径连接的情况。

在挤奶时间到来的时候,奶牛们开始从各自的放牧地点回到牛圈。放牧地点是指那些没有道路连接进来的路口(入度为0的顶点)。

现在请你帮助fj通过计算从放牧点到达牛圈的路径数目来找到最繁忙的道路(答案保证是不超过32位整数)。

思维固化了。

看到这题直接套上P1685 游览的板子。

才得60分。

再读题(看题解),发现这题会有多个起点,多个终点。

那么对于多个终点,只能去n,所以还要从n建反边跑一边拓扑排序,这样一条边的贡献就是\(g(u)*f(v)\)

好像我用了最笨的方法跑两边拓扑排序。

code:

#include <iostream>
#include <cstdio>
#include <queue>

using namespace std;

const int wx=500017;

inline int read(){
    int sum=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
    return sum*f;
}

int n,m,ans;
int num,tot;
int g[wx],head[wx],h[wx],f[wx];
int in[wx],out[wx],in2[wx],out2[wx];

struct e{
    int nxt,to;
}edge[wx*2];

void add(int from,int to){
    edge[++num].nxt=head[from];
    edge[num].to=to;
    head[from]=num;
}

struct ee{
    int nxt,to;
}e[wx*2];

void ADD(int from,int to){
    e[++tot].nxt=h[from];
    e[tot].to=to;
    h[from]=tot;
}

queue<int > q;

void bfs1(){
    for(int i=1;i<=n;i++)if(!in[i])g[i]=1,q.push(i);
    while(q.size()){
        int u=q.front(); q.pop();
        for(int i=head[u];i;i=edge[i].nxt){
            int v=edge[i].to;
            g[v]+=g[u];
            in[v]--;
            if(!in[v]){
                q.push(v);
            }
        }
    }
}

void bfs2(){
    for(int i=1;i<=n;i++)if(!in2[i])f[i]=1,q.push(i);
    while(q.size()){
        int u=q.front(); q.pop();
        for(int i=h[u];i;i=e[i].nxt){
            int v=e[i].to;
            f[v]+=f[u];
            in2[v]--;
            if(!in2[v])q.push(v);
        }
    }
    for(int u=1;u<=n;u++){
        for(int i=head[u];i;i=edge[i].nxt){
            int v=edge[i].to;
            ans=max(ans,g[u]*f[v]);
        }
    }
}

int main(){
    n=read(); m=read();
    for(int i=1;i<=m;i++){
        int x,y; 
        x=read(); y=read();
        if(x>y)swap(x,y);
        add(x,y); in[y]++; out[x]++;
        ADD(y,x); in2[x]++; out2[y]++;
    }
    bfs1();
    bfs2();
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/wangxiaodai/p/9811740.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值