传送门:NKOJ3250
这是一道网络流水题(水题过不了系列=-=)。
题解:首先跑最短路(SPFA,dijkstra),然后枚举每一条边判断它是否是在最短路上,再用最短路上的边建好图跑一次最大流即可。
感谢@Mogician_Evian 帮我看丑代码。(模板题都要WA的我还是太菜了)
以下是我的丑代码:
#include<stdio.h>
#include<cstring>
#include<queue>
#include<cmath>
#define LL long long
const LL inf=1e18;
const int MAXN=505<<1;
const int MAXM=100005<<1;
using namespace std;
LL n,m,A[MAXM],B[MAXM],D[MAXM];
LL Last[MAXN],Next[MAXM],To[MAXM],pid;
LL Len[MAXM];
void Storepath(LL u,LL v,LL l){
To[++pid]=v,Next[pid]=Last[u],Last[u]=pid,Len[pid]=l;
}
queue<LL>Q;
LL dis[MAXN][3];
bool ifin[MAXN];
void SPFA(LL St,LL fl){
for(int i=2;i<=n;i++)dis[i][fl]=inf;
dis[St][fl]=0,Q.push(St),ifin[St]=1;
LL tmp;
while(Q.size()){
tmp=Q.front(),Q.pop(),ifin[tmp]=0;
for(int i=Last[tmp];i;i=Next[i]){
if(dis[To[i]][fl]>dis[tmp][fl]+Len[i]){
dis[To[i]][fl]=dis[tmp][fl]+Len[i];
if(!ifin[To[i]]){
Q.push(To[i]),ifin[To[i]]=1;
}
}
}
}
}
int CNT[MAXN],DIS[MAXN],START,END;
LL W[MAXN],WW,ANS,WWW[MAXN][MAXN];
LL SAP(LL U,LL FLOW){
if(U==END)return FLOW;
LL OUT=0,TMP;
for(int I=1;I<=n;I++){
if(DIS[I]+1!=DIS[U]||WWW[U][I]<=0)continue;
OUT+=TMP=SAP(I,min(FLOW-OUT,WWW[U][I]));
WWW[U][I]-=TMP,WWW[I][U]+=TMP;
if(OUT==FLOW||DIS[START]>=END)return OUT;
}
if(!--CNT[DIS[U]])DIS[START]=END;
CNT[++DIS[U]]++;
return OUT;
}
LL ORZ[MAXN];
int main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++){
scanf("%lld%lld%lld",&A[i],&B[i],&D[i]);
Storepath(A[i],B[i],D[i]),Storepath(B[i],A[i],D[i]);
}
SPFA(1,1),SPFA(n,2);
for(int i=1;i<=n;i++)scanf("%lld",&ORZ[i]);
ORZ[1]=ORZ[n]=inf;
for(int i=1;i<=m;i++)
if(dis[A[i]][1]+D[i]+dis[B[i]][2]==dis[n][1]||dis[B[i]][1]+D[i]+dis[A[i]][2]==dis[n][1])
WWW[A[i]][B[i]]=WWW[B[i]][A[i]]=min(ORZ[A[i]],ORZ[B[i]]);
START=1,END=n;
while(DIS[START]<END)ANS+=SAP(START,inf);
printf("%lld",ANS);
return 0;
}