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; }