【bzoj3931】【CQOI2015】【网络吞吐量】【spfa+最大流】

Description

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

Input

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

Output

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

Sample Input

7 10
1 2 2
1 5 2
2 4 1
2 3 3
3 7 1
4 5 4
4 3 1
4 6 1
5 6 2
6 7 1
1
100
20
50
20
60
1

Sample Output

70

HINT

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

题解:建出最短路图之后拆点跑最大流即可.

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 510
#define M 100010
#define ll long long
#define inf 12345678987654321ll
using namespace std;
int n,x,y,v,m,cnt,T,num=1,f[N],q[N*20],next[M<<2],point[N];
int cur[N<<1],d[N<<1],head[N<<1],gap[N<<1],pre[N<<1];
long long dis[N],a[N];
struct use{
  int st,en;
  long long v;
}e[M<<1],b[M<<1];
int read(){
  int x(0);char ch=getchar();
  while (ch<'0'||ch>'9') ch=getchar();
  while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
  return x; 
}
void add(int x,int y,ll v){
  //cout<<"!"<<x<<' '<<y<<' '<<v<<endl;
  next[++cnt]=point[x];point[x]=cnt;
  e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;
}
void ins(int x,int y,ll v){
    //cout<<x<<' '<<y<<' '<<v<<endl;
  next[++num]=head[x];head[x]=num;
  b[num].st=x;b[num].en=y;b[num].v=v;
  next[++num]=head[y];head[y]=num;
  b[num].st=y;b[num].en=x;b[num].v=0;
}
void spfa(){
  int h(0),t(1);
  memset(dis,127,sizeof(dis));
  q[t]=1;dis[1]=0;f[1]=1;
  while (h<t){
    int u=q[++h];f[u]=0;
    for (int i=point[u];i;i=next[i])
      if (dis[e[i].en]>dis[u]+e[i].v){ 
        dis[e[i].en]=dis[u]+e[i].v;
        if (!f[e[i].en]){
          f[e[i].en]=1;
          q[++t]=e[i].en;
        }
      }
  }
}
ll isap(){
  int u(1),i;
  ll ans(0);gap[0]=T;
  for (int i=1;i<=T;i++) cur[i]=head[i];
  while(d[1]<T){
    bool f(0);
    for (i=cur[u];i;i=next[i]) 
      if (d[b[i].en]+1==d[u]&&b[i].v){f=1;cur[u]=i;break;}
    if (f){
      pre[u=b[i].en]=i;
      if (u==T){
        ll mn=inf;
        for (int i=T;i!=1;i=b[pre[i]].st) mn=min(mn,b[pre[i]].v);
        ans+=mn;
        for (int i=T;i!=1;i=b[pre[i]].st) b[pre[i]].v-=mn,b[pre[i]^1].v+=mn;
        u=1;
      }
    }
    else{
      --gap[d[u]];if (!gap[d[u]]) return ans;
      int mn=T;
      for (i=head[u];i;i=next[i])
        if (b[i].v) mn=min(mn,d[b[i].en]);
      gap[d[u]=mn+1]++;cur[u]=head[u];if (u!=1) u=b[pre[u]].st; 
    }
  }
  return ans;
}
int main(){
  n=read();m=read();
  for (int i=1;i<=m;i++){
    x=read();y=read();v=read();
    add(x,y,v);add(y,x,v);
  }     
  spfa();memset(next,0,sizeof(next));
  for (int i=1;i<=n;i++) a[i]=(ll)read();a[1]=a[n]=inf;
  for (int i=1;i<=n;i++) ins(i,i+n,a[i]);
  for (int i=1;i<=cnt;i++)
    if (dis[e[i].en]==dis[e[i].st]+e[i].v)
       ins(e[i].st+n,e[i].en,inf);      
  T=n+n;
  cout<<isap();
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值