洛谷 P3171 [CQOI2015]网络吞吐量 解题报告

P3171 [CQOI2015]网络吞吐量

题目描述

路由是指通过计算机网络把信息从源地址传输到目的地址的活动,也是计算机网络设计中的重点和难点。网络中实现路由转发的硬件设备称为路由器。为了使数据包最快的到达目的地,路由器需要选择最优的路径转发数据包。例如在常用的路由算法OSPF(开放式最短路径优先)中,路由器会使用经典的Dijkstra算法计算最短路径,然后尽量沿最短路径转发数据包。现在,若已知一个计算机网络中各路由器间的连接情况,以及各个路由器的最大吞吐量(即每秒能转发的数据包数量),假设所有数据包一定沿最短路径转发,试计算从路由器1到路由器n的网络的最大吞吐量。计算中忽略转发及传输的时间开销,不考虑链路的带宽限制,即认为数据包可以瞬间通过网络。路由器1到路由器n作为起点和终点,自身的吞吐量不用考虑,网络上也不存在将1和n直接相连的链路。

输入输出格式

输入格式:

输入文件第一行包含两个空格分开的正整数n和m,分别表示路由器数量和链路的数量。网络中的路由器使用1到n编号。接下来m行,每行包含三个空格分开的正整数a、b和d,表示从路由器a到路由器b存在一条距离为d的双向链路。 接下来n行,每行包含一个正整数c,分别给出每一个路由器的吞吐量。

输出格式:

输出一个整数,为题目所求吞吐量。

说明

对于100%的数据,n<=500,m<=100000,d,c<=10^9


get到题意是第一步,最短路径其实只需要1-n的就可以了。

我们先正反做一编最短路,把所有在最短路上的边抽出来建新图。

把每个点拆开,边权为点的吞吐量,其余边只是保证联通性,故置inf即可


Code:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#define ll long long
using namespace std;
#define P pair <ll ,int >
const int N=502;
const int M=200010;
const ll inf=0x3f3f3f3f3f3f3f3f;
int n,m,used[N];
ll diss[N],dist[N],inout[N],edge0[M],edge[M<<1];
int head0[N],to0[M],Next0[M],cnt0;
void add0(int u,int v,ll w)
{
    to0[++cnt0]=v;Next0[cnt0]=head0[u];edge0[cnt0]=w;head0[u]=cnt0;
}
int head[N<<1],to[M<<1],Next[M<<1],cnt=1;
void add(int u,int v,ll w)
{
    to[++cnt]=v;Next[cnt]=head[u];edge[cnt]=w;head[u]=cnt;
}
priority_queue <P,vector<P >,greater<P > >  q0;
P p;
void disj()
{
    memset(diss,0x3f,sizeof(diss));
    memset(used,0,sizeof(used));
    diss[1]=0;
    p.first=0,p.second=1;
    q0.push(p);
    while(!q0.empty())
    {
        int u=q0.top().second;
        q0.pop();
        if(used[u]) continue;
        used[u]=1;
        for(int i=head0[u];i;i=Next0[i])
        {
            int v=to0[i];
            ll w=edge0[i];
            if(diss[v]>diss[u]+w)
            {
                diss[v]=diss[u]+w;
                p.first=diss[v],p.second=v;
                q0.push(p);
            }
        }
    }
    memset(dist,0x3f,sizeof(diss));
    memset(used,0,sizeof(used));
    dist[n]=0;
    p.first=0,p.second=n;
    q0.push(p);
    while(!q0.empty())
    {
        int u=q0.top().second;
        q0.pop();
        if(used[u]) continue;
        used[u]=1;
        for(int i=head0[u];i;i=Next0[i])
        {
            int v=to0[i];
            ll w=edge0[i];
            if(dist[v]>dist[u]+w)
            {
                dist[v]=dist[u]+w;
                p.first=dist[v],p.second=v;
                q0.push(p);
            }
        }
    }
}
void New()
{
    for(int i=1;i<=n;i++)
    {
        add(i,i+n,inout[i]);
        add(i+n,i,0);
        for(int j=head0[i];j;j=Next0[j])
        {
            int v=to0[j];
            ll w=edge0[j];
            if(diss[i]+dist[v]+w==diss[n])
            {
                add(i+n,v,inf);
                add(v,i+n,0);
                //printf("%d %d %lld\n",i,v,inout[v]);
            }
        }
    }
}
void init()
{
    scanf("%d%d",&n,&m);
    int u,v;ll w;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%lld",&u,&v,&w);
        add0(u,v,w),add0(v,u,w);
    }
    for(int i=1;i<=n;i++)
        scanf("%lld",inout+i);
    inout[1]=inf;
    inout[n]=inf;
    disj();
    New();
}
int dep[N<<1];
queue <int > q;
bool bfs()
{
    memset(dep,0,sizeof(dep));
    dep[1]=1;
    while(!q.empty()) q.pop();
    q.push(1);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=Next[i])
        {
            int v=to[i];
            ll w=edge[i];
            if(w&&!dep[v])
            {
                dep[v]=dep[u]+1;
                if(v==n*2) return 1;
                q.push(v);
            }
        }
    }
    return 0;
}
ll dfs(int now,ll flow)
{
    if(now==n*2) return flow;
    ll k,rest=flow;
    for(int i=head[now];i&&rest;i=Next[i])
    {
        int v=to[i];
        if(edge[i]&&dep[v]==dep[now]+1)
        {
            k=dfs(v,min(rest,edge[i]));
            if(!k) dep[v]=0;
            edge[i]-=k;
            edge[i^1]+=k;
            rest-=k;
        }
    }
    return flow-rest;
}
void work()
{
    ll flow=0,maxflow=0;
    while(bfs())
        while(flow=dfs(1,inf))
            maxflow+=flow;
    printf("%lld\n",maxflow);
}
int main()
{
    init();
    work();
    return 0;
}

2018.7.7

转载于:https://www.cnblogs.com/butterflydew/p/9277382.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值