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
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
Source
题意比较简单,给出一个初始图,然后要你把所有最短路上的边保留,去掉其它的,然后求最大流。
本来想着求最短路的时候记录一下pre,,结果发现实际上这样只有一条路。
怎么办呢??
其实由于是单源的,我们直接O(N^2)可以处理出1~所有点的最短路径。
然后我们知道最短路是有最优子结构性质的,所以我们用dist[u]表示1~u的最短路,得到:
如果边(u,v)∈E,w(u,v)是u->v的权值,满足dist[u]+w(u,v)=dist[v],
那么(u,v)是某一条最短路上的边。
所以我们可以再建立一个新的图,然后在它上面求最大流了。
注意一下!
容量限制是点的,要转化为边,那么就裂点(拆点)吧。
还有1和n的容量限制是不用管的,开inf就好了。
由于是无向边……所以把。。。判断(u,v)之后还要再判断一遍(v,u)
最大流用了ISAP(以后就一直用它啦,就不说了)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll read(){
ll x=(ll)0,f=(ll)1;char ch=getchar();
while (ch<'0' || ch>'9'){if (ch=='-') f=(ll)-1;ch=getchar();}
while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int
MAX=100005;
const ll
inf=(ll)2000000005;
int n,m,Ecnt1,Ecnt2;
int Ver,source,sink;
ll dist[MAX],w[MAX];
int u[MAX],v[MAX],gap[MAX],Q[MAX];
int cur[MAX],pre[MAX],vv[MAX],d[MAX];
bool vis[MAX];
struct Edge1{
int next,to;
ll val;
}E1[MAX<<1]; int head1[MAX];
struct Edge2{
int next,to;
ll C;
}E2[MAX<<1]; int head2[MAX];
void add1(int u,int v,ll w){
E1[Ecnt1].next=head1[u];
E1[Ecnt1].to=v;
E1[Ecnt1].val=w;
head1[u]=Ecnt1++;
}
void add2(int u,int v,ll w){
E2[Ecnt2].next=head2[u];
E2[Ecnt2].to=v;
E2[Ecnt2].C=w;
head2[u]=Ecnt2++;
}
void dijkstra(){
memset(dist,127,sizeof(dist));
memset(vis,0,sizeof(vis));
dist[1]=(ll)0; int mini;
for (int i=1;i<=n;i++){
mini=0;
for (int j=1;j<=n;j++)
if (!vis[j] && dist[mini]>dist[j]) mini=j;
vis[mini]=1;
for (int j=head1[mini];~j;j=E1[j].next)
if (dist[E1[j].to]>dist[mini]+E1[j].val)
dist[E1[j].to]=dist[mini]+E1[j].val;
}
}
void build(){
Ecnt2=Ver=0;
memset(head2,255,sizeof(head2));
memset(vis,0,sizeof(vis));
for (int i=1;i<=m;i++)
if (dist[u[i]]+w[i]==dist[v[i]]){
add2(u[i]<<1,v[i]<<1|1,inf),add2(v[i]<<1|1,u[i]<<1,(ll)0);
if (!vis[u[i]]) Ver++;
if (!vis[v[i]]) Ver++;
vis[u[i]]=vis[v[i]]=1;
} else
if (dist[v[i]]+w[i]==dist[u[i]]){
add2(v[i]<<1,u[i]<<1|1,inf),add2(u[i]<<1|1,v[i]<<1,(ll)0);
if (!vis[u[i]]) Ver++;
if (!vis[v[i]]) Ver++;
vis[u[i]]=vis[v[i]]=1;
}
for (int i=1;i<=n;i++)
add2(i<<1|1,i<<1,(ll)vv[i]),add2(i<<1,i<<1|1,0);
}
void BFS(){
memset(gap,0,sizeof(gap));
memset(d,255,sizeof(d));
d[sink]=0; gap[0]++;
int head=0,tail=1;
Q[0]=sink;
while (head!=tail){
int u=Q[head++];
for (int i=head2[u];~i;i=E2[i].next){
int j=E2[i].to;
if (~d[j]) continue;
d[j]=d[u]+1;
gap[d[j]]++;
Q[tail++]=j;
}
}
}
ll ISAP(){
BFS();
memcpy(cur,head2,sizeof(cur));
int u; ll flow=(ll)0;
u=pre[source]=source;
while (d[sink]<Ver+1){
if (u==sink){
ll f=inf;
int neck;
for (int i=source;i!=sink;i=E2[cur[i]].to)
if (f>E2[cur[i]].C) f=E2[cur[i]].C,neck=i;
for (int i=source;i!=sink;i=E2[cur[i]].to)
E2[cur[i]].C-=f,E2[cur[i]^1].C+=f;
flow+=f; u=neck;
}
int j;
for (j=cur[u];~j;j=E2[j].next)
if (E2[j].C && d[E2[j].to]+1==d[u]) break;
if (~j){
pre[E2[j].to]=u;
cur[u]=j;
u=E2[j].to;
} else{
if (!(--gap[d[u]])) break;
int mind=Ver+1;
for (int i=head2[u];~i;i=E2[i].next)
if (E2[i].C && mind>d[E2[i].to])
cur[u]=i,mind=d[E2[i].to];
d[u]=mind+1;
gap[d[u]]++;
u=pre[u];
}
}
return flow;
}
int main(){
n=read(),m=read();
Ecnt1=0;
memset(head1,255,sizeof(head1));
for (int i=1;i<=m;i++){
u[i]=read(),v[i]=read(),w[i]=read();
add1(u[i],v[i],w[i]); add1(v[i],u[i],w[i]);
}
for (int i=1;i<=n;i++) vv[i]=read();
dijkstra();
vv[1]=vv[n]=inf;
build();
source=2,sink=n<<1|1;
printf("%lld\n",ISAP());
return 0;
}