NC19939 [CQOI2015]网络吞吐量
题目:
• 路由是指通过计算机网络把信息从源地址传输到目的地址的活动,也是计算机网络设计中的重点和难点。网络中实现路由转发的硬件设备称为路由器。为了使数据包最快的到达目的地,路由器需要选择最优的路径转发数据包。例如在常用的路由算法OSPF(开放式最短路径优先)中,路由器会使用经典的Dijkstra算法计算最短路径,然后尽量沿最短路径转发数据包。
• 现在,若已知一个计算机网络中各路由器间的连接情况,以及各个路由器的最大吞吐量(即每秒能转发的数据包数量),假设所有数据包一定沿最短路径转发,试计算从路由器1到路由器n的网络的最大吞吐量。计算中忽略转发及传输的时间开销,不考虑链路的带宽限制,即认为数据包可以瞬间通过网络。路由器1到路由器n作为起点和终点,自身的吞吐量不用考虑,网络上也不存在将1和n直接相连的链路。
• n<=500,m<=100000
题解:
第一反应是最小费用最大流,但其实并不是
题目要求的是在最短路的基础上求最大吞吐量
若我们要走1到n的最短路,那我们只能走dis[v]=dis[u]+edge[u][v]的边
所以我们第一步就跑遍最短路,保留最短路中的边,此时边权我们就可以忽略掉了,因为之后再也用不上
题目中吞吐量的限制与平常不一样,这里不是对边而是对点,对点的话没办法直接算,我们可以将点一分为二,将n个点拆成n*2个点,然后第i个点向第i+n个点建立一个容量为A[i]的边
然后对于最短路中的边e[u][v],我们从第u+n个点向第v个点建一条容量为inf的边
从源点s向点1建一条容量为inf的边
从点2n向汇点t建立一条容量为inf的边
然后跑最大流即可
本题的特殊之处就在于先用最短路处理一下,剩下的步骤都是最大流常规操作了、
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
#define inf 0x7fffffffff/2
#define eps 1e-6
#define N 2010
#define M 100010
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
inline ll read()
{
char ch=getchar();
ll s=0,w=1;
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s*w;
}
ll dist[N];
struct edge
{
int next,to;
ll fl;
}e[M<<1];
int cnt=1,head[N];
int n,m;
int vis[N];
ll c[N];
int s,t;
int depth[N];
queue<int>Q;
vector<int>to[N];
vector<ll>v[N];
inline void add_edge(int from,int to,ll fl)
{
e[++cnt].to=to;
e[cnt].next=head[from];
e[cnt].fl=fl;
head[from]=cnt;
}
inline int bfs()
{
while(!Q.empty())Q.pop();memset(depth,0,sizeof(depth));
Q.push(s);depth[s]=1;
while(!Q.empty())
{
int x=Q.front();Q.pop();
for(register int i=head[x];i;i=e[i].next)
{
if(!depth[e[i].to]&&e[i].fl>0)
{
depth[e[i].to]=depth[x]+1;
Q.push(e[i].to);
}
}
}
return depth[t];
}
ll dfs(int now,ll flow)
{
if(now==t)return flow;
ll ret=0;
for(register int i=head[now];i;i=e[i].next)
{
if(ret==flow)return ret;
if(depth[e[i].to]==depth[now]+1&&e[i].fl>0)
{
ll fl=dfs(e[i].to,min(flow-ret,e[i].fl));
if(fl>0)
{
ret+=fl;
e[i].fl-=fl;
e[i^1].fl+=fl;
}
}
}
return ret;
}
inline ll Dinic()
{
ll sum=0;
while(bfs())
{
ll x=1;while(x){x=dfs(s,inf);sum+=x;}
}
return sum;
}
inline void spfa()
{
for(register int i=2;i<=n;i++)dist[i]=inf;
while(!Q.empty())Q.pop();
Q.push(1);vis[1]=1;
while(!Q.empty())
{
int x=Q.front();Q.pop();vis[x]=0;
for(register int i=0;i<to[x].size();i++)
{
int go=to[x][i];
ll val=v[x][i];
if(dist[x]+val<dist[go])
{
dist[go]=dist[x]+val;
if(!vis[go])
{
vis[go]=1;
Q.push(go);
}
}
}
}
}
int main()
{
n=read(),m=read();
t=n*2+1;
for(register int i=1;i<=m;i++)
{
int x=read(),y=read();
ll val=read();
to[x].push_back(y);v[x].push_back(val);
to[y].push_back(x);v[y].push_back(val);
}
spfa();
for(register int i=1;i<=n;i++)c[i]=read();
add_edge(s,1,inf);add_edge(1,s,0);
add_edge(2*n,t,inf);add_edge(t,2*n,0);
for(register int i=1;i<=n;i++)
{
if(i!=1&&i!=n)
{
add_edge(i,i+n,c[i]);
add_edge(i+n,i,0);
}
else
{
add_edge(i,i+n,inf);
add_edge(i+n,i,0);
}
}//通过拆点对每个点经过的流量进行限制
for(register int i=1;i<=n;i++)
{
for(register int j=0;j<to[i].size();j++)
{
int go=to[i][j];
ll val=v[i][j];
if(dist[go]==dist[i]+val)//在最短路中
{
add_edge(i+n,go,inf);
add_edge(go,i+n,0);
}
}
}//对在最短路中的边建边
printf("%lld\n",Dinic());
return 0;
}
京公网安备 11010502036488号